Skip to content

Unreachable propagation: preserve information about unreachable values #77800

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 12 additions & 23 deletions compiler/rustc_mir/src/transform/unreachable_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,7 @@ use std::borrow::Cow;
pub struct UnreachablePropagation;

impl MirPass<'_> for UnreachablePropagation {
fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
// Enable only under -Zmir-opt-level=3 as in some cases (check the deeply-nested-opt
// perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
return;
}

fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut unreachable_blocks = FxHashSet::default();
let mut replacements = FxHashMap::default();

Expand Down Expand Up @@ -50,10 +44,12 @@ impl MirPass<'_> for UnreachablePropagation {
}

let replaced = !replacements.is_empty();
for bb in unreachable_blocks {
body.basic_blocks_mut()[bb].statements.clear();
}
for (bb, terminator_kind) in replacements {
body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind;
}

if replaced {
simplify::remove_dead_blocks(body);
}
Expand All @@ -62,40 +58,33 @@ impl MirPass<'_> for UnreachablePropagation {

fn remove_successors<F>(
terminator_kind: &TerminatorKind<'tcx>,
predicate: F,
is_unreachable: F,
) -> Option<TerminatorKind<'tcx>>
where
F: Fn(BasicBlock) -> bool,
{
let terminator = match *terminator_kind {
TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
TerminatorKind::Goto { target } if is_unreachable(target) => TerminatorKind::Unreachable,
TerminatorKind::SwitchInt { ref discr, switch_ty, ref values, ref targets } => {
let original_targets_len = targets.len();
let (otherwise, targets) = targets.split_last().unwrap();
let (mut values, mut targets): (Vec<_>, Vec<_>) =
values.iter().zip(targets.iter()).filter(|(_, &t)| !predicate(t)).unzip();

if !predicate(*otherwise) {
targets.push(*otherwise);
} else {
values.pop();
if !is_unreachable(*otherwise) {
return None;
}

let retained_targets_len = targets.len();
let (values, mut targets): (Vec<_>, Vec<_>) =
values.iter().zip(targets.iter()).filter(|(_, &t)| !is_unreachable(t)).unzip();

if targets.is_empty() {
TerminatorKind::Unreachable
} else if targets.len() == 1 {
TerminatorKind::Goto { target: targets[0] }
} else if original_targets_len != retained_targets_len {
} else {
targets.push(*otherwise);
TerminatorKind::SwitchInt {
discr: discr.clone(),
switch_ty,
values: Cow::from(values),
targets,
}
} else {
return None;
}
}
_ => return None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,52 +37,56 @@
StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17
_8 = discriminant((_3.0: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17
switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17
switchInt(move _8) -> [0_isize: bb1, 1_isize: bb4, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17
}

bb1: {
_6 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23
switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23
switchInt(move _6) -> [0_isize: bb2, 1_isize: bb7, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23
}

bb2: {
_0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26
goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
}

bb3: {
_7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26
switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26
unreachable; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17
}

bb4: {
_7 = discriminant((_3.1: std::option::Option<u32>)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26
switchInt(move _7) -> [0_isize: bb6, 1_isize: bb5, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26
}

bb5: {
StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
_9 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16
StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25
_10 = (((_3.1: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25
_0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32
goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
}

bb5: {
bb6: {
StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
_11 = (((_3.0: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16
_0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29
goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
}

bb6: {
bb7: {
StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
_12 = (((_3.1: std::option::Option<u32>) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22
_0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29
goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
goto -> bb8; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6
}

bb7: {
bb8: {
StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2
return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2
}
Expand Down
28 changes: 16 additions & 12 deletions src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
_3 = const 1_isize; // scope 0 at $DIR/issue-73223.rs:3:9: 3:16
goto -> bb2; // scope 0 at $DIR/issue-73223.rs:3:9: 3:16
goto -> bb3; // scope 0 at $DIR/issue-73223.rs:3:9: 3:16
}

bb1: {
Expand All @@ -110,6 +110,10 @@
}

bb2: {
unreachable; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
}

bb3: {
StorageLive(_4); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
_4 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
_1 = _4; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21
Expand Down Expand Up @@ -153,10 +157,10 @@
StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
_15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
}

bb3: {
bb4: {
_8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
Expand All @@ -169,7 +173,7 @@
return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
}

bb4: {
bb5: {
StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL
Expand Down Expand Up @@ -220,24 +224,24 @@
StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_46 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}

bb5: {
bb6: {
StorageDead(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}

bb6: {
bb7: {
StorageDead(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
(_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
(_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
Expand All @@ -256,24 +260,24 @@
StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_50 = transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute::<for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar(<ZST>)) }
}

bb7: {
bb8: {
StorageDead(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
_52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// mir::Constant
// + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL
// + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar(<ZST>)) }
}

bb8: {
bb9: {
StorageDead(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
(_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
(_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@

bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:13:9: 13:13
}

bb1: {
_0 = const 1_u8; // scope 0 at $DIR/matches_u8.rs:14:17: 14:18
goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
goto -> bb4; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
}

bb2: {
_0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18
goto -> bb3; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
unreachable; // scope 0 at $DIR/matches_u8.rs:12:11: 12:12
}

bb3: {
_0 = const 0_u8; // scope 0 at $DIR/matches_u8.rs:13:17: 13:18
goto -> bb4; // scope 0 at $DIR/matches_u8.rs:12:5: 15:6
}

bb4: {
return; // scope 0 at $DIR/matches_u8.rs:16:2: 16:2
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,24 @@

bb0: {
_2 = discriminant(_1); // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
switchInt(move _2) -> [0_isize: bb3, 1_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/matches_u8.rs:21:9: 21:13
}

bb1: {
_0 = const 1_i8; // scope 0 at $DIR/matches_u8.rs:22:17: 22:18
goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
goto -> bb4; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
}

bb2: {
_0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18
goto -> bb3; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
unreachable; // scope 0 at $DIR/matches_u8.rs:20:11: 20:12
}

bb3: {
_0 = const 0_i8; // scope 0 at $DIR/matches_u8.rs:21:17: 21:18
goto -> bb4; // scope 0 at $DIR/matches_u8.rs:20:5: 23:6
}

bb4: {
return; // scope 0 at $DIR/matches_u8.rs:24:2: 24:2
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
_3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL
StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
_5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
}

bb1: {
Expand All @@ -71,6 +71,10 @@
}

bb2: {
unreachable; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15
}

bb3: {
- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15
- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ fn process_never(_1: *const !) -> () {
}

bb0: {
StorageLive(_2); // scope 0 at $DIR/uninhabited-enum.rs:8:8: 8:14
_2 = &(*_1); // scope 2 at $DIR/uninhabited-enum.rs:8:26: 8:33
StorageDead(_2); // scope 0 at $DIR/uninhabited-enum.rs:9:1: 9:2
unreachable; // scope 0 at $DIR/uninhabited-enum.rs:7:39: 9:2
}
}
Loading