about summary refs log tree commit diff
diff options
context:
space:
mode:
authorCamille GILLOT <gillot.camille@gmail.com>2023-02-26 13:42:28 +0000
committerCamille GILLOT <gillot.camille@gmail.com>2024-02-09 21:13:53 +0000
commit014b29eecfbe79e4a6ca6d845907ebebeee53f1d (patch)
treec51abcf70cb692d9fed244978d8816dfe3d84774
parente132cac3c45217f5f2b730ddd684fdd4700ffc4c (diff)
downloadrust-014b29eecfbe79e4a6ca6d845907ebebeee53f1d.tar.gz
rust-014b29eecfbe79e4a6ca6d845907ebebeee53f1d.zip
Remove ConstGoto and SeparateConstSwitch.
-rw-r--r--compiler/rustc_mir_transform/src/const_goto.rs128
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs7
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs343
-rw-r--r--tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff50
-rw-r--r--tests/mir-opt/const_goto.rs19
-rw-r--r--tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff51
-rw-r--r--tests/mir-opt/const_goto_const_eval_fail.f.JumpThreading.diff47
-rw-r--r--tests/mir-opt/const_goto_const_eval_fail.rs2
-rw-r--r--tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff102
-rw-r--r--tests/mir-opt/const_goto_storage.rs22
-rw-r--r--tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir22
-rw-r--r--tests/mir-opt/pre-codegen/matches_macro.rs27
-rw-r--r--tests/mir-opt/separate_const_switch.identity.JumpThreading.diff (renamed from tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff)19
-rw-r--r--tests/mir-opt/separate_const_switch.rs4
-rw-r--r--tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff (renamed from tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff)15
15 files changed, 125 insertions, 733 deletions
diff --git a/compiler/rustc_mir_transform/src/const_goto.rs b/compiler/rustc_mir_transform/src/const_goto.rs
deleted file mode 100644
index cb5b66b314d..00000000000
--- a/compiler/rustc_mir_transform/src/const_goto.rs
+++ /dev/null
@@ -1,128 +0,0 @@
-//! This pass optimizes the following sequence
-//! ```rust,ignore (example)
-//! bb2: {
-//!     _2 = const true;
-//!     goto -> bb3;
-//! }
-//!
-//! bb3: {
-//!     switchInt(_2) -> [false: bb4, otherwise: bb5];
-//! }
-//! ```
-//! into
-//! ```rust,ignore (example)
-//! bb2: {
-//!     _2 = const true;
-//!     goto -> bb5;
-//! }
-//! ```
-
-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 is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // This pass participates in some as-of-yet untested unsoundness found
-        // in https://github.com/rust-lang/rust/issues/112460
-        sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts
-    }
-
-    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 block = &mut body.basic_blocks_mut()[opt.bb_with_goto];
-            block.statements.extend(opt.stmts_move_up);
-            let terminator = block.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<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) {
-        if data.is_cleanup {
-            // Because of the restrictions around control flow in cleanup blocks, we don't perform
-            // this optimization at all in such blocks.
-            return;
-        }
-        self.super_basic_block_data(block, data);
-    }
-
-    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];
-
-                // The `StorageDead(..)` statement does not affect the functionality of mir.
-                // We can move this part of the statement up to the predecessor.
-                let mut stmts_move_up = Vec::new();
-                for stmt in &target_bb.statements {
-                    if let StatementKind::StorageDead(..) = stmt.kind {
-                        stmts_move_up.push(stmt.clone())
-                    } else {
-                        None?;
-                    }
-                }
-
-                let target_bb_terminator = target_bb.terminator();
-                let (discr, targets) = target_bb_terminator.kind.as_switch()?;
-                if discr.place() == Some(*place) {
-                    let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
-                    debug_assert_eq!(switch_ty, _const.ty());
-                    // 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.const_.try_eval_bits(self.tcx, self.param_env)?;
-                    let target_to_use_in_goto = targets.target_for_value(const_value);
-                    self.optimizations.push(OptimizationToApply {
-                        bb_with_goto: location.block,
-                        target_to_use_in_goto,
-                        stmts_move_up,
-                    });
-                }
-            }
-            Some(())
-        };
-
-        self.super_terminator(terminator, location);
-    }
-}
-
-struct OptimizationToApply<'tcx> {
-    bb_with_goto: BasicBlock,
-    target_to_use_in_goto: BasicBlock,
-    stmts_move_up: Vec<Statement<'tcx>>,
-}
-
-pub struct ConstGotoOptimizationFinder<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    optimizations: Vec<OptimizationToApply<'tcx>>,
-}
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index 8e5d69605aa..281bf3d44e6 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -59,7 +59,6 @@ mod remove_place_mention;
 mod add_subtyping_projections;
 pub mod cleanup_post_borrowck;
 mod const_debuginfo;
-mod const_goto;
 mod const_prop;
 mod const_prop_lint;
 mod copy_prop;
@@ -103,7 +102,6 @@ mod remove_unneeded_drops;
 mod remove_zsts;
 mod required_consts;
 mod reveal_all;
-mod separate_const_switch;
 mod shim;
 mod ssa;
 // This pass is public to allow external drivers to perform MIR cleanup
@@ -590,7 +588,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
 
             // Has to run after `slice::len` lowering
             &normalize_array_len::NormalizeArrayLen,
-            &const_goto::ConstGoto,
             &ref_prop::ReferencePropagation,
             &sroa::ScalarReplacementOfAggregates,
             &match_branches::MatchBranchSimplification,
@@ -601,10 +598,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
             &dead_store_elimination::DeadStoreElimination::Initial,
             &gvn::GVN,
             &simplify::SimplifyLocals::AfterGVN,
-            // Perform `SeparateConstSwitch` after SSA-based analyses, as cloning blocks may
-            // destroy the SSA property. It should still happen before const-propagation, so the
-            // latter pass will leverage the created opportunities.
-            &separate_const_switch::SeparateConstSwitch,
             &dataflow_const_prop::DataflowConstProp,
             &const_debuginfo::ConstDebugInfo,
             &o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
deleted file mode 100644
index 7120ef72142..00000000000
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ /dev/null
@@ -1,343 +0,0 @@
-//! A pass that duplicates switch-terminated blocks
-//! into a new copy for each predecessor, provided
-//! the predecessor sets the value being switched
-//! over to a constant.
-//!
-//! The purpose of this pass is to help constant
-//! propagation passes to simplify the switch terminator
-//! of the copied blocks into gotos when some predecessors
-//! statically determine the output of switches.
-//!
-//! ```text
-//!     x = 12 ---              ---> something
-//!               \            / 12
-//!                --> switch x
-//!               /            \ otherwise
-//!     x = y  ---              ---> something else
-//! ```
-//! becomes
-//! ```text
-//!     x = 12 ---> switch x ------> something
-//!                          \ / 12
-//!                           X
-//!                          / \ otherwise
-//!     x = y  ---> switch x ------> something else
-//! ```
-//! so it can hopefully later be turned by another pass into
-//! ```text
-//!     x = 12 --------------------> something
-//!                            / 12
-//!                           /
-//!                          /   otherwise
-//!     x = y  ---- switch x ------> something else
-//! ```
-//!
-//! This optimization is meant to cover simple cases
-//! like `?` desugaring. For now, it thus focuses on
-//! simplicity rather than completeness (it notably
-//! sometimes duplicates abusively).
-
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use smallvec::SmallVec;
-
-pub struct SeparateConstSwitch;
-
-impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
-    fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
-        // This pass participates in some as-of-yet untested unsoundness found
-        // in https://github.com/rust-lang/rust/issues/112460
-        sess.mir_opt_level() >= 2 && sess.opts.unstable_opts.unsound_mir_opts
-    }
-
-    fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // If execution did something, applying a simplification layer
-        // helps later passes optimize the copy away.
-        if separate_const_switch(body) > 0 {
-            super::simplify::simplify_cfg(body);
-        }
-    }
-}
-
-/// Returns the amount of blocks that were duplicated
-pub fn separate_const_switch(body: &mut Body<'_>) -> usize {
-    let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
-    let predecessors = body.basic_blocks.predecessors();
-    'block_iter: for (block_id, block) in body.basic_blocks.iter_enumerated() {
-        if let TerminatorKind::SwitchInt {
-            discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
-            ..
-        } = block.terminator().kind
-        {
-            // If the block is on an unwind path, do not
-            // apply the optimization as unwind paths
-            // rely on a unique parent invariant
-            if block.is_cleanup {
-                continue 'block_iter;
-            }
-
-            // If the block has fewer than 2 predecessors, ignore it
-            // we could maybe chain blocks that have exactly one
-            // predecessor, but for now we ignore that
-            if predecessors[block_id].len() < 2 {
-                continue 'block_iter;
-            }
-
-            // First, let's find a non-const place
-            // that determines the result of the switch
-            if let Some(switch_place) = find_determining_place(switch_place, block) {
-                // We now have an input place for which it would
-                // be interesting if predecessors assigned it from a const
-
-                let mut predecessors_left = predecessors[block_id].len();
-                'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() {
-                    let predecessor = &body.basic_blocks[predecessor_id];
-
-                    // First we make sure the predecessor jumps
-                    // in a reasonable way
-                    match &predecessor.terminator().kind {
-                        // The following terminators are
-                        // unconditionally valid
-                        TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {}
-
-                        TerminatorKind::FalseEdge { real_target, .. } => {
-                            if *real_target != block_id {
-                                continue 'predec_iter;
-                            }
-                        }
-
-                        // The following terminators are not allowed
-                        TerminatorKind::UnwindResume
-                        | TerminatorKind::Drop { .. }
-                        | TerminatorKind::Call { .. }
-                        | TerminatorKind::Assert { .. }
-                        | TerminatorKind::FalseUnwind { .. }
-                        | TerminatorKind::Yield { .. }
-                        | TerminatorKind::UnwindTerminate(_)
-                        | TerminatorKind::Return
-                        | TerminatorKind::Unreachable
-                        | TerminatorKind::InlineAsm { .. }
-                        | TerminatorKind::CoroutineDrop => {
-                            continue 'predec_iter;
-                        }
-                    }
-
-                    if is_likely_const(switch_place, predecessor) {
-                        new_blocks.push((predecessor_id, block_id));
-                        predecessors_left -= 1;
-                        if predecessors_left < 2 {
-                            // If the original block only has one predecessor left,
-                            // we have nothing left to do
-                            break 'predec_iter;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // Once the analysis is done, perform the duplication
-    let body_span = body.span;
-    let copied_blocks = new_blocks.len();
-    let blocks = body.basic_blocks_mut();
-    for (pred_id, target_id) in new_blocks {
-        let new_block = blocks[target_id].clone();
-        let new_block_id = blocks.push(new_block);
-        let terminator = blocks[pred_id].terminator_mut();
-
-        match terminator.kind {
-            TerminatorKind::Goto { ref mut target } => {
-                *target = new_block_id;
-            }
-
-            TerminatorKind::FalseEdge { ref mut real_target, .. } => {
-                if *real_target == target_id {
-                    *real_target = new_block_id;
-                }
-            }
-
-            TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                targets.all_targets_mut().iter_mut().for_each(|x| {
-                    if *x == target_id {
-                        *x = new_block_id;
-                    }
-                });
-            }
-
-            TerminatorKind::UnwindResume
-            | TerminatorKind::UnwindTerminate(_)
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::CoroutineDrop
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::InlineAsm { .. }
-            | TerminatorKind::Yield { .. } => {
-                span_bug!(
-                    body_span,
-                    "basic block terminator had unexpected kind {:?}",
-                    &terminator.kind
-                )
-            }
-        }
-    }
-
-    copied_blocks
-}
-
-/// This function describes a rough heuristic guessing
-/// whether a place is last set with a const within the block.
-/// Notably, it will be overly pessimistic in cases that are already
-/// not handled by `separate_const_switch`.
-fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool {
-    for statement in block.statements.iter().rev() {
-        match &statement.kind {
-            StatementKind::Assign(assign) => {
-                if assign.0 == tracked_place {
-                    match assign.1 {
-                        // These rvalues are definitely constant
-                        Rvalue::Use(Operand::Constant(_))
-                        | Rvalue::Ref(_, _, _)
-                        | Rvalue::AddressOf(_, _)
-                        | Rvalue::Cast(_, Operand::Constant(_), _)
-                        | Rvalue::NullaryOp(_, _)
-                        | Rvalue::ShallowInitBox(_, _)
-                        | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
-
-                        // These rvalues make things ambiguous
-                        Rvalue::Repeat(_, _)
-                        | Rvalue::ThreadLocalRef(_)
-                        | Rvalue::Len(_)
-                        | Rvalue::BinaryOp(_, _)
-                        | Rvalue::CheckedBinaryOp(_, _)
-                        | Rvalue::Aggregate(_, _) => return false,
-
-                        // These rvalues move the place to track
-                        Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _)
-                        | Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
-                        | Rvalue::CopyForDeref(place)
-                        | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place))
-                        | Rvalue::Discriminant(place) => tracked_place = place,
-                    }
-                }
-            }
-
-            // If the discriminant is set, it is always set
-            // as a constant, so the job is done.
-            // As we are **ignoring projections**, if the place
-            // we are tracking sees its discriminant be set,
-            // that means we had to be tracking the discriminant
-            // specifically (as it is impossible to switch over
-            // an enum directly, and if we were switching over
-            // its content, we would have had to at least cast it to
-            // some variant first)
-            StatementKind::SetDiscriminant { place, .. } => {
-                if **place == tracked_place {
-                    return true;
-                }
-            }
-
-            // These statements have no influence on the place
-            // we are interested in
-            StatementKind::FakeRead(_)
-            | StatementKind::Deinit(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::Retag(_, _)
-            | StatementKind::AscribeUserType(_, _)
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::Intrinsic(_)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::Nop => {}
-        }
-    }
-
-    // If no good reason for the place to be const is found,
-    // give up. We could maybe go up predecessors, but in
-    // most cases giving up now should be sufficient.
-    false
-}
-
-/// Finds a unique place that entirely determines the value
-/// of `switch_place`, if it exists. This is only a heuristic.
-/// Ideally we would like to track multiple determining places
-/// for some edge cases, but one is enough for a lot of situations.
-fn find_determining_place<'tcx>(
-    mut switch_place: Place<'tcx>,
-    block: &BasicBlockData<'tcx>,
-) -> Option<Place<'tcx>> {
-    for statement in block.statements.iter().rev() {
-        match &statement.kind {
-            StatementKind::Assign(op) => {
-                if op.0 != switch_place {
-                    continue;
-                }
-
-                match op.1 {
-                    // The following rvalues move the place
-                    // that may be const in the predecessor
-                    Rvalue::Use(Operand::Move(new) | Operand::Copy(new))
-                    | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new))
-                    | Rvalue::CopyForDeref(new)
-                    | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _)
-                    | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _)
-                    | Rvalue::Discriminant(new)
-                    => switch_place = new,
-
-                    // The following rvalues might still make the block
-                    // be valid but for now we reject them
-                    Rvalue::Len(_)
-                    | Rvalue::Ref(_, _, _)
-                    | Rvalue::BinaryOp(_, _)
-                    | Rvalue::CheckedBinaryOp(_, _)
-                    | Rvalue::Aggregate(_, _)
-
-                    // The following rvalues definitely mean we cannot
-                    // or should not apply this optimization
-                    | Rvalue::Use(Operand::Constant(_))
-                    | Rvalue::Repeat(Operand::Constant(_), _)
-                    | Rvalue::ThreadLocalRef(_)
-                    | Rvalue::AddressOf(_, _)
-                    | Rvalue::NullaryOp(_, _)
-                    | Rvalue::ShallowInitBox(_, _)
-                    | Rvalue::UnaryOp(_, Operand::Constant(_))
-                    | Rvalue::Cast(_, Operand::Constant(_), _) => return None,
-                }
-            }
-
-            // These statements have no influence on the place
-            // we are interested in
-            StatementKind::FakeRead(_)
-            | StatementKind::Deinit(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::Retag(_, _)
-            | StatementKind::AscribeUserType(_, _)
-            | StatementKind::PlaceMention(..)
-            | StatementKind::Coverage(_)
-            | StatementKind::Intrinsic(_)
-            | StatementKind::ConstEvalCounter
-            | StatementKind::Nop => {}
-
-            // If the discriminant is set, it is always set
-            // as a constant, so the job is already done.
-            // As we are **ignoring projections**, if the place
-            // we are tracking sees its discriminant be set,
-            // that means we had to be tracking the discriminant
-            // specifically (as it is impossible to switch over
-            // an enum directly, and if we were switching over
-            // its content, we would have had to at least cast it to
-            // some variant first)
-            StatementKind::SetDiscriminant { place, .. } => {
-                if **place == switch_place {
-                    return None;
-                }
-            }
-        }
-    }
-
-    Some(switch_place)
-}
diff --git a/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff b/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff
deleted file mode 100644
index 43bdb431129..00000000000
--- a/tests/mir-opt/const_goto.issue_77355_opt.ConstGoto.diff
+++ /dev/null
@@ -1,50 +0,0 @@
-- // MIR for `issue_77355_opt` before ConstGoto
-+ // MIR for `issue_77355_opt` after ConstGoto
-  
-  fn issue_77355_opt(_1: Foo) -> u64 {
-      debug num => _1;
-      let mut _0: u64;
--     let mut _2: bool;
--     let mut _3: isize;
-+     let mut _2: isize;
-  
-      bb0: {
--         StorageLive(_2);
--         _3 = discriminant(_1);
--         switchInt(move _3) -> [1: bb2, 2: bb2, otherwise: bb1];
-+         _2 = discriminant(_1);
-+         switchInt(move _2) -> [1: bb2, 2: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
--         _2 = const false;
-+         _0 = const 42_u64;
-          goto -> bb3;
-      }
-  
-      bb2: {
--         _2 = const true;
-+         _0 = const 23_u64;
-          goto -> bb3;
-      }
-  
-      bb3: {
--         switchInt(move _2) -> [0: bb5, otherwise: bb4];
--     }
-- 
--     bb4: {
--         _0 = const 23_u64;
--         goto -> bb6;
--     }
-- 
--     bb5: {
--         _0 = const 42_u64;
--         goto -> bb6;
--     }
-- 
--     bb6: {
--         StorageDead(_2);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/const_goto.rs b/tests/mir-opt/const_goto.rs
deleted file mode 100644
index 93cb71c3a0f..00000000000
--- a/tests/mir-opt/const_goto.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-// skip-filecheck
-// unit-test: ConstGoto
-
-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/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff b/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff
deleted file mode 100644
index 84a13f28a31..00000000000
--- a/tests/mir-opt/const_goto_const_eval_fail.f.ConstGoto.diff
+++ /dev/null
@@ -1,51 +0,0 @@
-- // MIR for `f` before ConstGoto
-+ // MIR for `f` after ConstGoto
-  
-  fn f() -> u64 {
-      let mut _0: u64;
-      let mut _1: bool;
-      let mut _2: i32;
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
-          _2 = const A;
-          switchInt(_2) -> [1: bb2, 2: bb2, 3: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
-          _1 = const true;
-          goto -> bb3;
-      }
-  
-      bb2: {
-          _1 = const B;
--         goto -> bb3;
-+         switchInt(_1) -> [0: bb4, otherwise: bb3];
-      }
-  
-      bb3: {
--         switchInt(_1) -> [0: bb5, otherwise: bb4];
--     }
-- 
--     bb4: {
-          _0 = const 2_u64;
--         goto -> bb6;
-+         goto -> bb5;
-      }
-  
--     bb5: {
-+     bb4: {
-          _0 = const 1_u64;
--         goto -> bb6;
-+         goto -> bb5;
-      }
-  
--     bb6: {
-+     bb5: {
-          StorageDead(_2);
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/const_goto_const_eval_fail.f.JumpThreading.diff b/tests/mir-opt/const_goto_const_eval_fail.f.JumpThreading.diff
new file mode 100644
index 00000000000..4fc9254b7ba
--- /dev/null
+++ b/tests/mir-opt/const_goto_const_eval_fail.f.JumpThreading.diff
@@ -0,0 +1,47 @@
+- // MIR for `f` before JumpThreading
++ // MIR for `f` after JumpThreading
+  
+  fn f() -> u64 {
+      let mut _0: u64;
+      let mut _1: bool;
+  
+      bb0: {
+          StorageLive(_1);
+          switchInt(const A) -> [1: bb2, 2: bb2, 3: bb2, otherwise: bb1];
+      }
+  
+      bb1: {
+          _1 = const true;
+-         goto -> bb3;
++         goto -> bb7;
+      }
+  
+      bb2: {
+          _1 = const B;
+          goto -> bb3;
+      }
+  
+      bb3: {
+          switchInt(_1) -> [0: bb5, otherwise: bb4];
+      }
+  
+      bb4: {
+          _0 = const 2_u64;
+          goto -> bb6;
+      }
+  
+      bb5: {
+          _0 = const 1_u64;
+          goto -> bb6;
+      }
+  
+      bb6: {
+          StorageDead(_1);
+          return;
++     }
++ 
++     bb7: {
++         goto -> bb4;
+      }
+  }
+  
diff --git a/tests/mir-opt/const_goto_const_eval_fail.rs b/tests/mir-opt/const_goto_const_eval_fail.rs
index 869f916001c..c0e8e144b15 100644
--- a/tests/mir-opt/const_goto_const_eval_fail.rs
+++ b/tests/mir-opt/const_goto_const_eval_fail.rs
@@ -5,7 +5,7 @@
 // compile-flags: -Zunsound-mir-opts
 
 // If const eval fails, then don't crash
-// EMIT_MIR const_goto_const_eval_fail.f.ConstGoto.diff
+// EMIT_MIR const_goto_const_eval_fail.f.JumpThreading.diff
 pub fn f<const A: i32, const B: bool>() -> u64 {
     match {
         match A {
diff --git a/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
deleted file mode 100644
index 1768298d521..00000000000
--- a/tests/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff
+++ /dev/null
@@ -1,102 +0,0 @@
-- // MIR for `match_nested_if` before ConstGoto
-+ // MIR for `match_nested_if` after ConstGoto
-  
-  fn match_nested_if() -> bool {
-      let mut _0: bool;
-      let _1: bool;
--     let mut _2: ();
--     let mut _3: bool;
--     let mut _4: bool;
--     let mut _5: bool;
--     let mut _6: bool;
-+     let mut _2: bool;
-      scope 1 {
-          debug val => _1;
-      }
-  
-      bb0: {
-          StorageLive(_1);
-          StorageLive(_2);
--         _2 = ();
--         StorageLive(_3);
--         StorageLive(_4);
--         StorageLive(_5);
--         StorageLive(_6);
--         _6 = const true;
--         switchInt(move _6) -> [0: bb2, otherwise: bb1];
-+         _2 = const true;
-+         switchInt(move _2) -> [0: bb2, otherwise: bb1];
-      }
-  
-      bb1: {
--         _5 = const true;
-+         StorageDead(_2);
-+         _1 = const true;
-          goto -> bb3;
-      }
-  
-      bb2: {
--         _5 = const false;
-+         StorageDead(_2);
-+         _1 = const false;
-          goto -> bb3;
-      }
-  
-      bb3: {
--         switchInt(move _5) -> [0: bb5, otherwise: bb4];
--     }
-- 
--     bb4: {
--         StorageDead(_6);
--         _4 = const true;
--         goto -> bb6;
--     }
-- 
--     bb5: {
--         StorageDead(_6);
--         _4 = const false;
--         goto -> bb6;
--     }
-- 
--     bb6: {
--         switchInt(move _4) -> [0: bb8, otherwise: bb7];
--     }
-- 
--     bb7: {
--         StorageDead(_5);
--         _3 = const true;
--         goto -> bb9;
--     }
-- 
--     bb8: {
--         StorageDead(_5);
--         _3 = const false;
--         goto -> bb9;
--     }
-- 
--     bb9: {
--         switchInt(move _3) -> [0: bb11, otherwise: bb10];
--     }
-- 
--     bb10: {
--         StorageDead(_4);
--         StorageDead(_3);
--         _1 = const true;
--         goto -> bb12;
--     }
-- 
--     bb11: {
--         StorageDead(_4);
--         StorageDead(_3);
--         _1 = const false;
--         goto -> bb12;
--     }
-- 
--     bb12: {
--         StorageDead(_2);
-          _0 = _1;
-          StorageDead(_1);
-          return;
-      }
-  }
-  
diff --git a/tests/mir-opt/const_goto_storage.rs b/tests/mir-opt/const_goto_storage.rs
deleted file mode 100644
index 9d43da23990..00000000000
--- a/tests/mir-opt/const_goto_storage.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// skip-filecheck
-// unit-test: ConstGoto
-
-// EMIT_MIR const_goto_storage.match_nested_if.ConstGoto.diff
-fn match_nested_if() -> bool {
-    let val = match () {
-        () if if if if true { true } else { false } { true } else { false } {
-            true
-        } else {
-            false
-        } =>
-            {
-                true
-            }
-        _ => false,
-    };
-    val
-}
-
-fn main() {
-    let _ = match_nested_if();
-}
diff --git a/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir
new file mode 100644
index 00000000000..d41135c6a4f
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/matches_macro.issue_77355_opt.PreCodegen.after.mir
@@ -0,0 +1,22 @@
+// MIR for `issue_77355_opt` after PreCodegen
+
+fn issue_77355_opt(_1: Foo) -> u64 {
+    debug num => _1;
+    let mut _0: u64;
+    let mut _2: isize;
+
+    bb0: {
+        _2 = discriminant(_1);
+        switchInt(move _2) -> [1: bb1, 2: bb1, otherwise: bb2];
+    }
+
+    bb1: {
+        _0 = const 23_u64;
+        return;
+    }
+
+    bb2: {
+        _0 = const 42_u64;
+        return;
+    }
+}
diff --git a/tests/mir-opt/pre-codegen/matches_macro.rs b/tests/mir-opt/pre-codegen/matches_macro.rs
new file mode 100644
index 00000000000..42de2296571
--- /dev/null
+++ b/tests/mir-opt/pre-codegen/matches_macro.rs
@@ -0,0 +1,27 @@
+// This test verifies that the MIR we output using the `matches!()` macro is close
+// to the MIR for an `if let` branch.
+
+pub enum Foo {
+    A,
+    B,
+    C,
+    D,
+    E,
+    F,
+}
+
+// EMIT_MIR matches_macro.issue_77355_opt.PreCodegen.after.mir
+fn issue_77355_opt(num: Foo) -> u64 {
+    // CHECK-LABEL: fn issue_77355_opt(
+    // CHECK: switchInt({{.*}}) -> [1: bb1, 2: bb1, otherwise: bb2];
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = const 23_u64;
+    // CHECK-NEXT: return;
+    // CHECK: bb2: {
+    // CHECK-NEXT: _0 = const 42_u64;
+    // CHECK-NEXT: return;
+    if matches!(num, Foo::B | Foo::C) { 23 } else { 42 }
+}
+fn main() {
+    issue_77355_opt(Foo::A);
+}
diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff
index d2731615284..ab3d91ab918 100644
--- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff
+++ b/tests/mir-opt/separate_const_switch.identity.JumpThreading.diff
@@ -1,5 +1,5 @@
-- // MIR for `identity` before SeparateConstSwitch
-+ // MIR for `identity` after SeparateConstSwitch
+- // MIR for `identity` before JumpThreading
++ // MIR for `identity` after JumpThreading
   
   fn identity(_1: Result<i32, i32>) -> Result<i32, i32> {
       debug x => _1;
@@ -79,7 +79,8 @@
           StorageDead(_8);
           StorageDead(_3);
           _4 = discriminant(_2);
-          switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb6];
+-         switchInt(move _4) -> [0: bb1, 1: bb2, otherwise: bb6];
++         goto -> bb1;
       }
   
       bb4: {
@@ -88,7 +89,8 @@
           _11 = Result::<Infallible, i32>::Err(_10);
           _2 = ControlFlow::<Result<Infallible, i32>, i32>::Break(move _11);
           StorageDead(_11);
-          goto -> bb3;
+-         goto -> bb3;
++         goto -> bb7;
       }
   
       bb5: {
@@ -99,6 +101,15 @@
   
       bb6: {
           unreachable;
++     }
++ 
++     bb7: {
++         StorageDead(_10);
++         StorageDead(_9);
++         StorageDead(_8);
++         StorageDead(_3);
++         _4 = discriminant(_2);
++         goto -> bb2;
       }
   }
   
diff --git a/tests/mir-opt/separate_const_switch.rs b/tests/mir-opt/separate_const_switch.rs
index 3f43cdf4350..bad61d97475 100644
--- a/tests/mir-opt/separate_const_switch.rs
+++ b/tests/mir-opt/separate_const_switch.rs
@@ -6,7 +6,7 @@
 
 use std::ops::ControlFlow;
 
-// EMIT_MIR separate_const_switch.too_complex.SeparateConstSwitch.diff
+// EMIT_MIR separate_const_switch.too_complex.JumpThreading.diff
 fn too_complex(x: Result<i32, usize>) -> Option<i32> {
     // The pass should break the outer match into
     // two blocks that only have one parent each.
@@ -23,7 +23,7 @@ fn too_complex(x: Result<i32, usize>) -> Option<i32> {
     }
 }
 
-// EMIT_MIR separate_const_switch.identity.SeparateConstSwitch.diff
+// EMIT_MIR separate_const_switch.identity.JumpThreading.diff
 fn identity(x: Result<i32, i32>) -> Result<i32, i32> {
     Ok(x?)
 }
diff --git a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff
index 294bfa661cf..1ac527e9338 100644
--- a/tests/mir-opt/separate_const_switch.too_complex.SeparateConstSwitch.diff
+++ b/tests/mir-opt/separate_const_switch.too_complex.JumpThreading.diff
@@ -1,5 +1,5 @@
-- // MIR for `too_complex` before SeparateConstSwitch
-+ // MIR for `too_complex` after SeparateConstSwitch
+- // MIR for `too_complex` before JumpThreading
++ // MIR for `too_complex` after JumpThreading
   
   fn too_complex(_1: Result<i32, usize>) -> Option<i32> {
       debug x => _1;
@@ -33,7 +33,8 @@
       bb1: {
           _5 = ((_1 as Err).0: usize);
           _2 = ControlFlow::<usize, i32>::Break(_5);
-          goto -> bb3;
+-         goto -> bb3;
++         goto -> bb8;
       }
   
       bb2: {
@@ -44,7 +45,8 @@
   
       bb3: {
           _6 = discriminant(_2);
-          switchInt(move _6) -> [0: bb5, 1: bb4, otherwise: bb7];
+-         switchInt(move _6) -> [0: bb5, 1: bb4, otherwise: bb7];
++         goto -> bb5;
       }
   
       bb4: {
@@ -68,6 +70,11 @@
   
       bb7: {
           unreachable;
++     }
++ 
++     bb8: {
++         _6 = discriminant(_2);
++         goto -> bb4;
       }
   }