diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 05bcf2ba0ce49..0c9206f023860 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1498,7 +1498,14 @@ pub enum StatementKind<'tcx> { } impl<'tcx> StatementKind<'tcx> { - pub fn as_assign_mut(&mut self) -> Option<&mut Box<(Place<'tcx>, Rvalue<'tcx>)>> { + pub fn as_assign_mut(&mut self) -> Option<&mut (Place<'tcx>, Rvalue<'tcx>)> { + match self { + StatementKind::Assign(x) => Some(x), + _ => None, + } + } + + pub fn as_assign(&self) -> Option<&(Place<'tcx>, Rvalue<'tcx>)> { match self { StatementKind::Assign(x) => Some(x), _ => None, diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index c9493c679879e..0625980b798c8 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -407,6 +407,22 @@ impl<'tcx> TerminatorKind<'tcx> { | TerminatorKind::FalseUnwind { ref mut unwind, .. } => Some(unwind), } } + + pub fn as_switch(&self) -> Option<(&Operand<'tcx>, Ty<'tcx>, &SwitchTargets)> { + match self { + TerminatorKind::SwitchInt { discr, switch_ty, targets } => { + Some((discr, switch_ty, targets)) + } + _ => None, + } + } + + pub fn as_goto(&self) -> Option { + match self { + TerminatorKind::Goto { target } => Some(*target), + _ => None, + } + } } impl<'tcx> Debug for TerminatorKind<'tcx> { diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs new file mode 100644 index 0000000000000..8cb8031df7858 --- /dev/null +++ b/compiler/rustc_mir/src/transform/const_goto.rs @@ -0,0 +1,119 @@ +//! This pass optimizes the following sequence +//! ```rust +//! bb2: { +//! _2 = const true; +//! goto -> bb3; +//! } +//! +//! bb3: { +//! switchInt(_2) -> [false: bb4, otherwise: bb5]; +//! } +//! ``` +//! into +//! ```rust +//! bb2: { +//! _2 = const true; +//! goto -> bb5; +//! } +//! ``` + +use crate::transform::MirPass; +use rustc_middle::mir::*; +use rustc_middle::ty::TyCtxt; +use rustc_middle::{mir::visit::Visitor, ty::ParamEnv}; + +use super::simplify::{simplify_cfg, simplify_locals}; + +pub struct ConstGoto; + +impl<'tcx> MirPass<'tcx> for ConstGoto { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("Running ConstGoto on {:?}", body.source); + let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id()); + let mut opt_finder = + ConstGotoOptimizationFinder { tcx, body, optimizations: vec![], param_env }; + opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); + for opt in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[opt.bb_with_goto].terminator_mut(); + let new_goto = TerminatorKind::Goto { target: opt.target_to_use_in_goto }; + debug!("SUCCESS: replacing `{:?}` with `{:?}`", terminator.kind, new_goto); + terminator.kind = new_goto; + } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(body); + simplify_locals(body, tcx); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + let _: Option<_> = try { + let target = terminator.kind.as_goto()?; + // We only apply this optimization if the last statement is a const assignment + let last_statement = self.body.basic_blocks()[location.block].statements.last()?; + + if let (place, Rvalue::Use(Operand::Constant(_const))) = + last_statement.kind.as_assign()? + { + // We found a constant being assigned to `place`. + // Now check that the target of this Goto switches on this place. + let target_bb = &self.body.basic_blocks()[target]; + + // FIXME(simonvandel): We are conservative here when we don't allow + // any statements in the target basic block. + // This could probably be relaxed to allow `StorageDead`s which could be + // copied to the predecessor of this block. + if !target_bb.statements.is_empty() { + None? + } + + let target_bb_terminator = target_bb.terminator(); + let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?; + if discr.place() == Some(*place) { + // We now know that the Switch matches on the const place, and it is statementless + // Now find which value in the Switch matches the const value. + let const_value = + _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?; + let found_value_idx_option = targets + .iter() + .enumerate() + .find(|(_, (value, _))| const_value == *value) + .map(|(idx, _)| idx); + + let target_to_use_in_goto = + if let Some(found_value_idx) = found_value_idx_option { + targets.iter().nth(found_value_idx).unwrap().1 + } else { + // If we did not find the const value in values, it must be the otherwise case + targets.otherwise() + }; + + self.optimizations.push(OptimizationToApply { + bb_with_goto: location.block, + target_to_use_in_goto, + }); + } + } + Some(()) + }; + + self.super_terminator(terminator, location); + } +} + +struct OptimizationToApply { + bb_with_goto: BasicBlock, + target_to_use_in_goto: BasicBlock, +} + +pub struct ConstGotoOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + param_env: ParamEnv<'tcx>, + optimizations: Vec, +} diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs index 20b8c90a9dcad..be55fbf671aac 100644 --- a/compiler/rustc_mir/src/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -21,6 +21,7 @@ pub mod check_consts; pub mod check_packed_ref; pub mod check_unsafety; pub mod cleanup_post_borrowck; +pub mod const_goto; pub mod const_prop; pub mod deaggregator; pub mod dest_prop; @@ -388,6 +389,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ + &const_goto::ConstGoto, &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index f0c87bcf513cd..baab22436f908 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -315,48 +315,51 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } } -pub struct SimplifyLocals; - -impl<'tcx> MirPass<'tcx> for SimplifyLocals { - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { - trace!("running SimplifyLocals on {:?}", body.source); - - // First, we're going to get a count of *actual* uses for every `Local`. - // Take a look at `DeclMarker::visit_local()` to see exactly what is ignored. - let mut used_locals = { - let mut marker = DeclMarker::new(body); - marker.visit_body(&body); - - marker.local_counts - }; - - let arg_count = body.arg_count; +pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) { + // First, we're going to get a count of *actual* uses for every `Local`. + // Take a look at `DeclMarker::visit_local()` to see exactly what is ignored. + let mut used_locals = { + let mut marker = DeclMarker::new(body); + marker.visit_body(&body); + + marker.local_counts + }; + + let arg_count = body.arg_count; + + // Next, we're going to remove any `Local` with zero actual uses. When we remove those + // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` + // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from + // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a + // fixedpoint where there are no more unused locals. + loop { + let mut remove_statements = RemoveStatements::new(&mut used_locals, arg_count, tcx); + remove_statements.visit_body(body); + + if !remove_statements.modified { + break; + } + } - // Next, we're going to remove any `Local` with zero actual uses. When we remove those - // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals` - // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from - // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a - // fixedpoint where there are no more unused locals. - loop { - let mut remove_statements = RemoveStatements::new(&mut used_locals, arg_count, tcx); - remove_statements.visit_body(body); + // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. + let map = make_local_map(&mut body.local_decls, used_locals, arg_count); - if !remove_statements.modified { - break; - } - } + // Only bother running the `LocalUpdater` if we actually found locals to remove. + if map.iter().any(Option::is_none) { + // Update references to all vars and tmps now + let mut updater = LocalUpdater { map, tcx }; + updater.visit_body(body); - // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s. - let map = make_local_map(&mut body.local_decls, used_locals, arg_count); + body.local_decls.shrink_to_fit(); + } +} - // Only bother running the `LocalUpdater` if we actually found locals to remove. - if map.iter().any(Option::is_none) { - // Update references to all vars and tmps now - let mut updater = LocalUpdater { map, tcx }; - updater.visit_body(body); +pub struct SimplifyLocals; - body.local_decls.shrink_to_fit(); - } +impl<'tcx> MirPass<'tcx> for SimplifyLocals { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + trace!("running SimplifyLocals on {:?}", body.source); + simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs index 6372f8960ddb6..7a0f85a46ef6a 100644 --- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -76,7 +76,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral { // we convert the move in the comparison statement to a copy. // unwrap is safe as we know this statement is an assign - let box (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); + let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); use Operand::*; match rhs { diff --git a/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff b/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff new file mode 100644 index 0000000000000..b35bd0e55c5ef --- /dev/null +++ b/src/test/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff @@ -0,0 +1,52 @@ +- // MIR for `issue_77355_opt` before ConstGoto ++ // MIR for `issue_77355_opt` after ConstGoto + + fn issue_77355_opt(_1: Foo) -> u64 { + debug num => _1; // in scope 0 at $DIR/const_goto.rs:11:20: 11:23 + let mut _0: u64; // return place in scope 0 at $DIR/const_goto.rs:11:33: 11:36 +- let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- let mut _3: isize; // in scope 0 at $DIR/const_goto.rs:12:22: 12:28 ++ let mut _2: isize; // in scope 0 at $DIR/const_goto.rs:12:22: 12:28 + + bb0: { +- StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- _3 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:12:22: 12:28 +- switchInt(move _3) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto.rs:12:22: 12:28 ++ _2 = discriminant(_1); // scope 0 at $DIR/const_goto.rs:12:22: 12:28 ++ switchInt(move _2) -> [1_isize: bb2, 2_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto.rs:12:22: 12:28 + } + + bb1: { +- _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- } +- +- bb2: { +- _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL +- } +- +- bb3: { +- switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 +- } +- +- bb4: { + _0 = const 42_u64; // scope 0 at $DIR/const_goto.rs:12:53: 12:55 +- goto -> bb6; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 ++ goto -> bb3; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 + } + +- bb5: { ++ bb2: { + _0 = const 23_u64; // scope 0 at $DIR/const_goto.rs:12:41: 12:43 +- goto -> bb6; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 ++ goto -> bb3; // scope 0 at $DIR/const_goto.rs:12:5: 12:57 + } + +- bb6: { +- StorageDead(_2); // scope 0 at $DIR/const_goto.rs:13:1: 13:2 ++ bb3: { + return; // scope 0 at $DIR/const_goto.rs:13:2: 13:2 + } + } + diff --git a/src/test/mir-opt/const_goto.rs b/src/test/mir-opt/const_goto.rs new file mode 100644 index 0000000000000..939902e70e94b --- /dev/null +++ b/src/test/mir-opt/const_goto.rs @@ -0,0 +1,16 @@ +pub enum Foo { + A, + B, + C, + D, + E, + F, +} + +// EMIT_MIR const_goto.issue_77355_opt.ConstGoto.diff +fn issue_77355_opt(num: Foo) -> u64 { + if matches!(num, Foo::B | Foo::C) { 23 } else { 42 } +} +fn main() { + issue_77355_opt(Foo::A); +} diff --git a/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff b/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff new file mode 100644 index 0000000000000..f0103fc42025a --- /dev/null +++ b/src/test/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff @@ -0,0 +1,51 @@ +- // MIR for `f` before ConstGoto ++ // MIR for `f` after ConstGoto + + fn f() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/const_goto_const_eval_fail.rs:6:44: 6:47 + let mut _1: bool; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:7:11: 12:6 + let mut _2: i32; // in scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:11: 12:6 + StorageLive(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 + _2 = const A; // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:15: 8:16 + switchInt(_2) -> [1_i32: bb2, 2_i32: bb2, 3_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:9:13: 9:14 + } + + bb1: { + _1 = const true; // scope 0 at $DIR/const_goto_const_eval_fail.rs:10:18: 10:22 + goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:9: 11:10 + } + + bb2: { + _1 = const B; // scope 0 at $DIR/const_goto_const_eval_fail.rs:9:26: 9:27 +- goto -> bb3; // scope 0 at $DIR/const_goto_const_eval_fail.rs:8:9: 11:10 ++ switchInt(_1) -> [false: bb4, otherwise: bb3]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:9: 13:14 + } + + bb3: { +- switchInt(_1) -> [false: bb5, otherwise: bb4]; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:9: 13:14 +- } +- +- bb4: { + _0 = const 2_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:14:17: 14:18 +- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 15:6 ++ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 15:6 + } + +- bb5: { ++ bb4: { + _0 = const 1_u64; // scope 0 at $DIR/const_goto_const_eval_fail.rs:13:18: 13:19 +- goto -> bb6; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 15:6 ++ goto -> bb5; // scope 0 at $DIR/const_goto_const_eval_fail.rs:7:5: 15:6 + } + +- bb6: { ++ bb5: { + StorageDead(_2); // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:1: 16:2 + StorageDead(_1); // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:1: 16:2 + return; // scope 0 at $DIR/const_goto_const_eval_fail.rs:16:2: 16:2 + } + } + diff --git a/src/test/mir-opt/const_goto_const_eval_fail.rs b/src/test/mir-opt/const_goto_const_eval_fail.rs new file mode 100644 index 0000000000000..3b85fe6ab3cd9 --- /dev/null +++ b/src/test/mir-opt/const_goto_const_eval_fail.rs @@ -0,0 +1,16 @@ +#![feature(min_const_generics)] +#![crate_type = "lib"] + +// If const eval fails, then don't crash +// EMIT_MIR const_goto_const_eval_fail.f.ConstGoto.diff +pub fn f() -> u64 { + match { + match A { + 1 | 2 | 3 => B, + _ => true, + } + } { + false => 1, + true => 2, + } +} diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index ba963e3fe920b..0f6c77351b496 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -4,42 +4,23 @@ fn foo(_1: Option<()>) -> () { debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 - let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { - _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb2: { - _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - } - - bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - } - - bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index ba963e3fe920b..0f6c77351b496 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -4,42 +4,23 @@ fn foo(_1: Option<()>) -> () { debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 - let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ let mut _4: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + let mut _2: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ StorageLive(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _4 = move _3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ _2 = Eq(_4, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ StorageDead(_4); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { - _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb2: { - _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL goto -> bb3; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - } - - bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 - } - - bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff index dc3a6a36d9eef..33be4aabaab46 100644 --- a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -1,59 +1,35 @@ - // MIR for `opt` before InstCombine + // MIR for `opt` after InstCombine - fn opt(_1: Option<()>) -> bool { + fn opt(_1: bool) -> u32 { debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9 - let mut _0: bool; // return place in scope 0 at $DIR/not_equal_false.rs:3:26: 3:30 - let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - let mut _6: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - let mut _7: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - let mut _8: bool; // in scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + let mut _0: u32; // return place in scope 0 at $DIR/not_equal_false.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + let mut _3: bool; // in scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 bb0: { - StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - StorageLive(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - _6 = move _3; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - _2 = Eq(_6, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_6); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 - goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + StorageLive(_2); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + StorageLive(_3); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/not_equal_false.rs:4:8: 4:9 +- _2 = Ne(move _3, const false); // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 ++ _2 = move _3; // scope 0 at $DIR/not_equal_false.rs:4:8: 4:18 + StorageDead(_3); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:18 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:35 } bb1: { - _0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + _0 = const 1_u32; // scope 0 at $DIR/not_equal_false.rs:4:32: 4:33 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:35 } bb2: { - StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - StorageLive(_7); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - _7 = move _5; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - _4 = Eq(_7, const 1_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_7); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 - goto -> bb5; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + _0 = const 0_u32; // scope 0 at $DIR/not_equal_false.rs:4:21: 4:22 + goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:35 } bb3: { - StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 - StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:5:1: 5:2 return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 } - - bb4: { - switchInt(move _2) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - } - - bb5: { - StorageLive(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - _8 = move _4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 -- _0 = Ne(_8, const false); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 -+ _0 = _8; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - StorageDead(_8); // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - goto -> bb3; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 - } } diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs index a98a2834e8ec9..5fbb848dcb58b 100644 --- a/src/test/mir-opt/not_equal_false.rs +++ b/src/test/mir-opt/not_equal_false.rs @@ -1,9 +1,9 @@ // EMIT_MIR not_equal_false.opt.InstCombine.diff -fn opt(x: Option<()>) -> bool { - matches!(x, None) || matches!(x, Some(_)) +fn opt(x: bool) -> u32 { + if x != false { 0 } else { 1 } } fn main() { - opt(None); + opt(false); }