diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 07ce9d0cd9484..f1a76dd418948 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -558,6 +558,7 @@ fn test_debugging_options_tracking_hash() {
     tracked!(link_only, true);
     tracked!(merge_functions, Some(MergeFunctions::Disabled));
     tracked!(mir_emit_retag, true);
+    tracked!(mir_opt_skip_pass, vec!["ConstProp".to_owned()]);
     tracked!(mir_opt_level, 3);
     tracked!(mutable_noalias, true);
     tracked!(new_llvm_pass_manager, true);
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index c00c6860903c8..15ff9fff72a0f 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -34,13 +34,15 @@ extern crate tracing;
 #[macro_use]
 extern crate rustc_middle;
 
+#[macro_use]
+pub mod transform;
+
 mod borrow_check;
 pub mod const_eval;
 pub mod dataflow;
 pub mod interpret;
 pub mod monomorphize;
 mod shim;
-pub mod transform;
 pub mod util;
 
 use rustc_middle::ty::query::Providers;
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
index 5431d22e70320..87bf5fbf4c4cd 100644
--- a/compiler/rustc_mir/src/shim.rs
+++ b/compiler/rustc_mir/src/shim.rs
@@ -17,7 +17,7 @@ use std::iter;
 
 use crate::transform::{
     add_call_guards, add_moves_for_packed_drops, no_landing_pads, remove_noop_landing_pads,
-    run_passes, simplify,
+    simplify, PassManager,
 };
 use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
 use crate::util::expand_aggregate;
@@ -75,18 +75,15 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
     };
     debug!("make_shim({:?}) = untransformed {:?}", instance, result);
 
-    run_passes(
-        tcx,
-        &mut result,
-        MirPhase::Const,
-        &[&[
-            &add_moves_for_packed_drops::AddMovesForPackedDrops,
-            &no_landing_pads::NoLandingPads::new(tcx),
-            &remove_noop_landing_pads::RemoveNoopLandingPads,
-            &simplify::SimplifyCfg::new("make_shim"),
-            &add_call_guards::CriticalCallEdges,
-        ]],
-    );
+    if result.phase < MirPhase::Const {
+        run_passes!(PassManager::new(tcx, &mut result, MirPhase::Const) => [
+            add_moves_for_packed_drops::AddMovesForPackedDrops,
+            no_landing_pads::NoLandingPads::new(tcx),
+            remove_noop_landing_pads::RemoveNoopLandingPads,
+            simplify::SimplifyCfg::new("make_shim"),
+            add_call_guards::CriticalCallEdges,
+        ]);
+    }
 
     debug!("make_shim({:?}) = {:?}", instance, result);
 
diff --git a/compiler/rustc_mir/src/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs
index 1dddaeb89e684..c2c23d450a249 100644
--- a/compiler/rustc_mir/src/transform/add_call_guards.rs
+++ b/compiler/rustc_mir/src/transform/add_call_guards.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -31,6 +31,8 @@ pub use self::AddCallGuards::*;
  */
 
 impl<'tcx> MirPass<'tcx> for AddCallGuards {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         self.add_call_guards(body);
     }
diff --git a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
index 417e0a51aecf0..19ac48ba24482 100644
--- a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
@@ -1,7 +1,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util;
 use crate::util::patch::MirPatch;
 
@@ -39,6 +39,8 @@ use crate::util::patch::MirPatch;
 pub struct AddMovesForPackedDrops;
 
 impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("add_moves_for_packed_drops({:?} @ {:?})", body.source, body.span);
         add_moves_for_packed_drops(tcx, body);
diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs
index eec704e6cb775..a1338f7c8ca47 100644
--- a/compiler/rustc_mir/src/transform/add_retag.rs
+++ b/compiler/rustc_mir/src/transform/add_retag.rs
@@ -4,7 +4,7 @@
 //! of MIR building, and only after this pass we think of the program has having the
 //! normal MIR semantics.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -58,6 +58,8 @@ fn may_be_reference(ty: Ty<'tcx>) -> bool {
 }
 
 impl<'tcx> MirPass<'tcx> for AddRetag {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if !tcx.sess.opts.debugging_opts.mir_emit_retag {
             return;
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index 26993a6b941fb..99959b1a64c17 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -6,11 +6,14 @@ use rustc_middle::ty::TyCtxt;
 use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
 use rustc_span::def_id::DefId;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 
+// FIXME: This does not mutate the MIR, and should not be MIR pass.
 pub struct CheckConstItemMutation;
 
 impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut checker = ConstMutationChecker { body, tcx, target_local: None };
         checker.visit_body(&body);
diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs
index ee88daa83e783..bebf89b8d96de 100644
--- a/compiler/rustc_mir/src/transform/check_packed_ref.rs
+++ b/compiler/rustc_mir/src/transform/check_packed_ref.rs
@@ -3,12 +3,15 @@ use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util;
 
+// FIXME: This does not mutate the MIR, and should not be `MirPass`.
 pub struct CheckPackedRef;
 
 impl<'tcx> MirPass<'tcx> for CheckPackedRef {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let param_env = tcx.param_env(body.source.def_id());
         let source_info = SourceInfo::outermost(body.span);
diff --git a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
index 8ff0fae768618..ff6f4ad9e8a0f 100644
--- a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
@@ -18,7 +18,7 @@
 //! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
 //! [`Nop`]: rustc_middle::mir::StatementKind::Nop
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
 use rustc_middle::mir::{Statement, StatementKind};
@@ -31,6 +31,8 @@ pub struct DeleteNonCodegenStatements<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut delete = DeleteNonCodegenStatements { tcx };
         delete.visit_body(body);
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
index 14b310cda939e..0392bc2b2964e 100644
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ b/compiler/rustc_mir/src/transform/const_prop.rs
@@ -32,7 +32,7 @@ use crate::interpret::{
     InterpCx, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand,
     PlaceTy, Pointer, ScalarMaybeUninit, StackPopCleanup,
 };
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 
 /// The maximum number of bytes that we'll allocate space for a local or the return value.
 /// Needed for #66397, because otherwise we eval into large places and that can cause OOM or just
@@ -60,6 +60,9 @@ macro_rules! throw_machine_stop_str {
 pub struct ConstProp;
 
 impl<'tcx> MirPass<'tcx> for ConstProp {
+    // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // will be evaluated by miri and produce its errors there
         if body.source.promoted.is_some() {
diff --git a/compiler/rustc_mir/src/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs
index 4f44bb7b20476..403e2f06c8762 100644
--- a/compiler/rustc_mir/src/transform/copy_prop.rs
+++ b/compiler/rustc_mir/src/transform/copy_prop.rs
@@ -19,7 +19,7 @@
 //! (non-mutating) use of `SRC`. These restrictions are conservative and may be relaxed in the
 //! future.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::def_use::DefUseAnalysis;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{
@@ -30,15 +30,11 @@ use rustc_middle::ty::TyCtxt;
 pub struct CopyPropagation;
 
 impl<'tcx> MirPass<'tcx> for CopyPropagation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let opts = &tcx.sess.opts.debugging_opts;
-        // We only run when the MIR optimization level is > 1.
-        // This avoids a slow pass, and messing up debug info.
-        // FIXME(76740): This optimization is buggy and can cause unsoundness.
-        if opts.mir_opt_level <= 1 || !opts.unsound_mir_opts {
-            return;
-        }
+    // This pass is slow and doesn't handle debug info. It shouldn't run by default.
+    // FIXME(76740): This optimization is buggy and can cause unsoundness.
+    const LEVEL: OptLevel = OptLevel::Unsound;
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut def_use_analysis = DefUseAnalysis::new(body);
         loop {
             def_use_analysis.analyze(body);
diff --git a/compiler/rustc_mir/src/transform/deaggregator.rs b/compiler/rustc_mir/src/transform/deaggregator.rs
index 5bd7256c666c6..4250197bcd5ae 100644
--- a/compiler/rustc_mir/src/transform/deaggregator.rs
+++ b/compiler/rustc_mir/src/transform/deaggregator.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::expand_aggregate;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -6,6 +6,8 @@ use rustc_middle::ty::TyCtxt;
 pub struct Deaggregator;
 
 impl<'tcx> MirPass<'tcx> for Deaggregator {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
         let local_decls = &*local_decls;
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
index 410f462ed469f..cfa69574c9f6e 100644
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ b/compiler/rustc_mir/src/transform/dest_prop.rs
@@ -99,7 +99,7 @@
 use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
 use crate::dataflow::Analysis;
 use crate::{
-    transform::MirPass,
+    transform::{MirPass, OptLevel},
     util::{dump_mir, PassWhere},
 };
 use itertools::Itertools;
@@ -126,13 +126,11 @@ const MAX_BLOCKS: usize = 250;
 pub struct DestinationPropagation;
 
 impl<'tcx> MirPass<'tcx> for DestinationPropagation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove
-        // storage statements at the moment).
-        if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 {
-            return;
-        }
+    // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove
+    // storage statements at the moment).
+    const LEVEL: OptLevel = OptLevel::N(2);
 
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let def_id = body.source.def_id();
 
         let candidates = find_candidates(tcx, body);
diff --git a/compiler/rustc_mir/src/transform/dump_mir.rs b/compiler/rustc_mir/src/transform/dump_mir.rs
index 5b6edf17d06ab..64796719aa8cc 100644
--- a/compiler/rustc_mir/src/transform/dump_mir.rs
+++ b/compiler/rustc_mir/src/transform/dump_mir.rs
@@ -5,7 +5,7 @@ use std::fmt;
 use std::fs::File;
 use std::io;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util as mir_util;
 use rustc_middle::mir::Body;
 use rustc_middle::ty::TyCtxt;
@@ -14,6 +14,8 @@ use rustc_session::config::{OutputFilenames, OutputType};
 pub struct Marker(pub &'static str);
 
 impl<'tcx> MirPass<'tcx> for Marker {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn name(&self) -> Cow<'_, str> {
         Cow::Borrowed(self.0)
     }
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index 237a5c7864b1f..b24abc373a44a 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -1,4 +1,5 @@
-use crate::{transform::MirPass, util::patch::MirPatch};
+use crate::transform::{MirPass, OptLevel};
+use crate::util::patch::MirPatch;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{Ty, TyCtxt};
 use std::{borrow::Cow, fmt::Debug};
@@ -25,10 +26,9 @@ use super::simplify::simplify_cfg;
 pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
+    const LEVEL: OptLevel = OptLevel::N(2);
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
-            return;
-        }
         trace!("running EarlyOtherwiseBranch on {:?}", body.source);
         // we are only interested in this bb if the terminator is a switchInt
         let bbs_with_switch =
diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs
index 3d435f6d0e75a..8807971405408 100644
--- a/compiler/rustc_mir/src/transform/elaborate_drops.rs
+++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs
@@ -5,7 +5,7 @@ use crate::dataflow::on_lookup_result_bits;
 use crate::dataflow::MoveDataParamEnv;
 use crate::dataflow::{on_all_children_bits, on_all_drop_children_bits};
 use crate::dataflow::{Analysis, ResultsCursor};
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
 use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
 use crate::util::patch::MirPatch;
@@ -20,6 +20,8 @@ use std::fmt;
 pub struct ElaborateDrops;
 
 impl<'tcx> MirPass<'tcx> for ElaborateDrops {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
 
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
index 924bb4996fc35..560245153df75 100644
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ b/compiler/rustc_mir/src/transform/generator.rs
@@ -55,7 +55,7 @@ use crate::dataflow::impls::{
 use crate::dataflow::{self, Analysis};
 use crate::transform::no_landing_pads::no_landing_pads;
 use crate::transform::simplify;
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::dump_mir;
 use crate::util::expand_aggregate;
 use crate::util::storage;
@@ -1235,6 +1235,9 @@ fn create_cases<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for StateTransform {
+    // Even if we don't do optimizations, we still have to lower generators for codegen.
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let yield_ty = if let Some(yield_ty) = body.yield_ty {
             yield_ty
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
index bec1eb790478c..91e1afac19e8e 100644
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ b/compiler/rustc_mir/src/transform/inline.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyC
 use rustc_target::spec::abi::Abi;
 
 use super::simplify::{remove_dead_blocks, CfgSimplifier};
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use std::collections::VecDeque;
 use std::iter;
 
@@ -37,21 +37,21 @@ struct CallSite<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for Inline {
+    const LEVEL: OptLevel = OptLevel::N(2);
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 {
-            if tcx.sess.opts.debugging_opts.instrument_coverage {
-                // The current implementation of source code coverage injects code region counters
-                // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
-                // based function.
-                debug!("function inlining is disabled when compiling with `instrument_coverage`");
-            } else {
-                Inliner {
-                    tcx,
-                    param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
-                    codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
-                }
-                .run_pass(body);
+        if tcx.sess.opts.debugging_opts.instrument_coverage {
+            // The current implementation of source code coverage injects code region counters
+            // into the MIR, and assumes a 1-to-1 correspondence between MIR and source-code-
+            // based function.
+            debug!("function inlining is disabled when compiling with `instrument_coverage`");
+        } else {
+            Inliner {
+                tcx,
+                param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
+                codegen_fn_attrs: tcx.codegen_fn_attrs(body.source.def_id()),
             }
+            .run_pass(body);
         }
     }
 }
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
index 1a8e281d417df..cc5ad2345bcc6 100644
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ b/compiler/rustc_mir/src/transform/instcombine.rs
@@ -1,6 +1,6 @@
 //! Performs various peephole optimizations.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::Mutability;
 use rustc_index::vec::Idx;
@@ -19,6 +19,8 @@ use std::mem;
 pub struct InstCombine;
 
 impl<'tcx> MirPass<'tcx> for InstCombine {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
         // read-only so that we can do global analyses on the MIR in the process (e.g.
diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs
index babe10a0f14da..1fac80278c8a1 100644
--- a/compiler/rustc_mir/src/transform/instrument_coverage.rs
+++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::pretty;
 use crate::util::spanview::{self, SpanViewable};
 
@@ -88,6 +88,8 @@ fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo
 }
 
 impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
         // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
         // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
index dad3812c5cd74..5ce251b249ffd 100644
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ b/compiler/rustc_mir/src/transform/match_branches.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
@@ -37,6 +37,8 @@ pub struct MatchBranchSimplification;
 /// ```
 
 impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let param_env = tcx.param_env(body.source.def_id());
         let bbs = body.basic_blocks_mut();
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index b4f5947f5a339..622350f029c89 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -11,8 +11,13 @@ use rustc_middle::ty::query::Providers;
 use rustc_middle::ty::steal::Steal;
 use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
 use rustc_span::{Span, Symbol};
-use std::borrow::Cow;
 
+#[macro_use]
+mod pass;
+
+pub use self::pass::{MirPass, OptLevel, PassManager};
+
+// Passes
 pub mod add_call_guards;
 pub mod add_moves_for_packed_drops;
 pub mod add_retag;
@@ -134,82 +139,6 @@ fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> FxHashSet<LocalDefId> {
     set
 }
 
-/// Generates a default name for the pass based on the name of the
-/// type `T`.
-pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
-    let name = ::std::any::type_name::<T>();
-    if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
-}
-
-/// A streamlined trait that you can implement to create a pass; the
-/// pass will be named after the type, and it will consist of a main
-/// loop that goes over each available MIR and applies `run_pass`.
-pub trait MirPass<'tcx> {
-    fn name(&self) -> Cow<'_, str> {
-        default_name::<Self>()
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
-}
-
-pub fn run_passes(
-    tcx: TyCtxt<'tcx>,
-    body: &mut Body<'tcx>,
-    mir_phase: MirPhase,
-    passes: &[&[&dyn MirPass<'tcx>]],
-) {
-    let phase_index = mir_phase.phase_index();
-    let validate = tcx.sess.opts.debugging_opts.validate_mir;
-
-    if body.phase >= mir_phase {
-        return;
-    }
-
-    if validate {
-        validate::Validator { when: format!("input to phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, body);
-    }
-
-    let mut index = 0;
-    let mut run_pass = |pass: &dyn MirPass<'tcx>| {
-        let run_hooks = |body: &_, index, is_after| {
-            dump_mir::on_mir_pass(
-                tcx,
-                &format_args!("{:03}-{:03}", phase_index, index),
-                &pass.name(),
-                body,
-                is_after,
-            );
-        };
-        run_hooks(body, index, false);
-        pass.run_pass(tcx, body);
-        run_hooks(body, index, true);
-
-        if validate {
-            validate::Validator {
-                when: format!("after {} in phase {:?}", pass.name(), mir_phase),
-                mir_phase,
-            }
-            .run_pass(tcx, body);
-        }
-
-        index += 1;
-    };
-
-    for pass_group in passes {
-        for pass in *pass_group {
-            run_pass(*pass);
-        }
-    }
-
-    body.phase = mir_phase;
-
-    if mir_phase == MirPhase::Optimization {
-        validate::Validator { when: format!("end of phase {:?}", mir_phase), mir_phase }
-            .run_pass(tcx, body);
-    }
-}
-
 fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
     let const_kind = tcx.hir().body_const_context(def.did);
 
@@ -259,19 +188,15 @@ fn mir_const<'tcx>(
 
     util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
 
-    run_passes(
-        tcx,
-        &mut body,
-        MirPhase::Const,
-        &[&[
-            // MIR-level lints.
-            &check_packed_ref::CheckPackedRef,
-            &check_const_item_mutation::CheckConstItemMutation,
-            // What we need to do constant evaluation.
-            &simplify::SimplifyCfg::new("initial"),
-            &rustc_peek::SanityCheck,
-        ]],
-    );
+    run_passes!(PassManager::new(tcx, &mut body, MirPhase::Const) => [
+        // MIR-level lints.
+        check_packed_ref::CheckPackedRef,
+        check_const_item_mutation::CheckConstItemMutation,
+        // What we need to do constant evaluation.
+        simplify::SimplifyCfg::new("initial"),
+        rustc_peek::SanityCheck,
+    ]);
+
     tcx.alloc_steal_mir(body)
 }
 
@@ -301,20 +226,19 @@ fn mir_promoted(
     }
     body.required_consts = required_consts;
 
+    let mut promotion_passes = PassManager::new(tcx, &mut body, MirPhase::ConstPromotion);
+
     let promote_pass = promote_consts::PromoteTemps::default();
-    let promote: &[&dyn MirPass<'tcx>] = &[
-        // What we need to run borrowck etc.
-        &promote_pass,
-        &simplify::SimplifyCfg::new("promote-consts"),
-    ];
-
-    let opt_coverage: &[&dyn MirPass<'tcx>] = if tcx.sess.opts.debugging_opts.instrument_coverage {
-        &[&instrument_coverage::InstrumentCoverage]
-    } else {
-        &[]
-    };
+    run_passes!(promotion_passes => [
+        promote_pass,
+        simplify::SimplifyCfg::new("promote-consts"),
+    ]);
+
+    if tcx.sess.opts.debugging_opts.instrument_coverage {
+        run_passes!(promotion_passes => [instrument_coverage::InstrumentCoverage]);
+    }
 
-    run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
+    drop(promotion_passes);
 
     let promoted = promote_pass.promoted_fragments.into_inner();
     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
@@ -348,30 +272,28 @@ fn mir_drops_elaborated_and_const_checked<'tcx>(
 fn run_post_borrowck_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     debug!("post_borrowck_cleanup({:?})", body.source.def_id());
 
-    let post_borrowck_cleanup: &[&dyn MirPass<'tcx>] = &[
+    run_passes!(PassManager::new(tcx, body, MirPhase::DropLowering) => [
         // Remove all things only needed by analysis
-        &no_landing_pads::NoLandingPads::new(tcx),
-        &simplify_branches::SimplifyBranches::new("initial"),
-        &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &cleanup_post_borrowck::CleanupNonCodegenStatements,
-        &simplify::SimplifyCfg::new("early-opt"),
+        no_landing_pads::NoLandingPads::new(tcx),
+        simplify_branches::SimplifyBranches::new("initial"),
+        remove_noop_landing_pads::RemoveNoopLandingPads,
+        cleanup_post_borrowck::CleanupNonCodegenStatements,
+        simplify::SimplifyCfg::new("early-opt"),
         // These next passes must be executed together
-        &add_call_guards::CriticalCallEdges,
-        &elaborate_drops::ElaborateDrops,
-        &no_landing_pads::NoLandingPads::new(tcx),
+        add_call_guards::CriticalCallEdges,
+        elaborate_drops::ElaborateDrops,
+        no_landing_pads::NoLandingPads::new(tcx),
         // AddMovesForPackedDrops needs to run after drop
         // elaboration.
-        &add_moves_for_packed_drops::AddMovesForPackedDrops,
+        add_moves_for_packed_drops::AddMovesForPackedDrops,
         // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
         // but before optimizations begin.
-        &add_retag::AddRetag,
-        &simplify::SimplifyCfg::new("elaborate-drops"),
+        add_retag::AddRetag,
+        simplify::SimplifyCfg::new("elaborate-drops"),
         // `Deaggregator` is conceptually part of MIR building, some backends rely on it happening
         // and it can help optimizations.
-        &deaggregator::Deaggregator,
-    ];
-
-    run_passes(tcx, body, MirPhase::DropLowering, &[post_borrowck_cleanup]);
+        deaggregator::Deaggregator,
+    ]);
 }
 
 fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
@@ -380,80 +302,54 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     // Lowering generator control-flow and variables has to happen before we do anything else
     // to them. We run some optimizations before that, because they may be harder to do on the state
     // machine than on MIR with async primitives.
-    let optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[
-        &unreachable_prop::UnreachablePropagation,
-        &uninhabited_enum_branching::UninhabitedEnumBranching,
-        &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
-        &inline::Inline,
-        &generator::StateTransform,
-    ];
-
-    // Even if we don't do optimizations, we still have to lower generators for codegen.
-    let no_optimizations_with_generators: &[&dyn MirPass<'tcx>] = &[&generator::StateTransform];
-
-    // The main optimizations that we do on MIR.
-    let optimizations: &[&dyn MirPass<'tcx>] = &[
-        &remove_unneeded_drops::RemoveUnneededDrops,
-        &match_branches::MatchBranchSimplification,
-        // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
-        &multiple_return_terminators::MultipleReturnTerminators,
-        &instcombine::InstCombine,
-        &const_prop::ConstProp,
-        &simplify_branches::SimplifyBranches::new("after-const-prop"),
-        &early_otherwise_branch::EarlyOtherwiseBranch,
-        &simplify_comparison_integral::SimplifyComparisonIntegral,
-        &simplify_try::SimplifyArmIdentity,
-        &simplify_try::SimplifyBranchSame,
-        &dest_prop::DestinationPropagation,
-        &copy_prop::CopyPropagation,
-        &simplify_branches::SimplifyBranches::new("after-copy-prop"),
-        &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &simplify::SimplifyCfg::new("final"),
-        &nrvo::RenameReturnPlace,
-        &simplify::SimplifyLocals,
-        &multiple_return_terminators::MultipleReturnTerminators,
-    ];
-
-    // Optimizations to run even if mir optimizations have been disabled.
-    let no_optimizations: &[&dyn MirPass<'tcx>] = &[
-        // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
-        &const_prop::ConstProp,
-    ];
+    run_passes!(PassManager::new(tcx, body, MirPhase::GeneratorLowering) => [
+        unreachable_prop::UnreachablePropagation,
+        uninhabited_enum_branching::UninhabitedEnumBranching,
+        simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
+        inline::Inline,
+        generator::StateTransform,
+    ]);
+
+    let mut optimizations = PassManager::new(tcx, body, MirPhase::Optimization);
+
+    // FIXME(ecstaticmorse): We shouldn't branch on `mir_opt_level` here, but instead rely on the
+    // `LEVEL` of each `MirPass` to determine whether it runs. However, this would run some
+    // "cleanup" passes as well as `RemoveNoopLandingPads` when we didn't before.
+    if mir_opt_level > 0 {
+        run_passes!(optimizations => [
+            remove_unneeded_drops::RemoveUnneededDrops,
+            match_branches::MatchBranchSimplification,
+            // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
+            multiple_return_terminators::MultipleReturnTerminators,
+            instcombine::InstCombine,
+            const_prop::ConstProp,
+            simplify_branches::SimplifyBranches::new("after-const-prop"),
+            early_otherwise_branch::EarlyOtherwiseBranch,
+            simplify_comparison_integral::SimplifyComparisonIntegral,
+            simplify_try::SimplifyArmIdentity,
+            simplify_try::SimplifyBranchSame,
+            dest_prop::DestinationPropagation,
+            copy_prop::CopyPropagation,
+            simplify_branches::SimplifyBranches::new("after-copy-prop"),
+            remove_noop_landing_pads::RemoveNoopLandingPads,
+            simplify::SimplifyCfg::new("final"),
+            nrvo::RenameReturnPlace,
+            simplify::SimplifyLocals,
+            multiple_return_terminators::MultipleReturnTerminators,
+        ]);
+    } else {
+        run_passes!(optimizations => [
+            // FIXME(#70073): This pass is responsible for both optimization as well as some lints.
+            const_prop::ConstProp,
+        ]);
+    }
 
     // Some cleanup necessary at least for LLVM and potentially other codegen backends.
-    let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
-        &add_call_guards::CriticalCallEdges,
+    run_passes!(optimizations => [
+        add_call_guards::CriticalCallEdges,
         // Dump the end result for testing and debugging purposes.
-        &dump_mir::Marker("PreCodegen"),
-    ];
-
-    // End of pass declarations, now actually run the passes.
-    // Generator Lowering
-    #[rustfmt::skip]
-    run_passes(
-        tcx,
-        body,
-        MirPhase::GeneratorLowering,
-        &[
-            if mir_opt_level > 0 {
-                optimizations_with_generators
-            } else {
-                no_optimizations_with_generators
-            }
-        ],
-    );
-
-    // Main optimization passes
-    #[rustfmt::skip]
-    run_passes(
-        tcx,
-        body,
-        MirPhase::Optimization,
-        &[
-            if mir_opt_level > 0 { optimizations } else { no_optimizations },
-            pre_codegen_cleanup,
-        ],
-    );
+        dump_mir::Marker("PreCodegen"),
+    ]);
 }
 
 fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
index c37b54a3190f8..9be113b114d33 100644
--- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
+++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
@@ -1,7 +1,7 @@
 //! This pass removes jumps to basic blocks containing only a return, and replaces them with a
 //! return instead.
 
-use crate::transform::{simplify, MirPass};
+use crate::transform::{simplify, MirPass, OptLevel};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -9,11 +9,9 @@ use rustc_middle::ty::TyCtxt;
 pub struct MultipleReturnTerminators;
 
 impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.opts.debugging_opts.mir_opt_level < 3 {
-            return;
-        }
+    const LEVEL: OptLevel = OptLevel::N(3);
 
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // find basic blocks with no statement and a return terminator
         let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
         let bbs = body.basic_blocks_mut();
diff --git a/compiler/rustc_mir/src/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs
index 83954c93c04a1..00d668d49d09d 100644
--- a/compiler/rustc_mir/src/transform/no_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/no_landing_pads.rs
@@ -1,7 +1,7 @@
 //! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
 //! specified.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -18,6 +18,8 @@ impl<'tcx> NoLandingPads<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for NoLandingPads<'tcx> {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         no_landing_pads(tcx, body)
     }
diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs
index 7e05d66074bb1..0b440086dd83d 100644
--- a/compiler/rustc_mir/src/transform/nrvo.rs
+++ b/compiler/rustc_mir/src/transform/nrvo.rs
@@ -4,7 +4,7 @@ use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}
 use rustc_middle::mir::{self, BasicBlock, Local, Location};
 use rustc_middle::ty::TyCtxt;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 
 /// This pass looks for MIR that always copies the same local into the return place and eliminates
 /// the copy by renaming all uses of that local to `_0`.
@@ -31,6 +31,8 @@ use crate::transform::MirPass;
 pub struct RenameReturnPlace;
 
 impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
         if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
             return;
diff --git a/compiler/rustc_mir/src/transform/pass.rs b/compiler/rustc_mir/src/transform/pass.rs
new file mode 100644
index 0000000000000..71832b64d40f8
--- /dev/null
+++ b/compiler/rustc_mir/src/transform/pass.rs
@@ -0,0 +1,162 @@
+use std::borrow::Cow;
+
+use rustc_middle::mir::{Body, MirPhase};
+use rustc_middle::ty::TyCtxt;
+
+use super::{dump_mir, validate};
+
+/// A streamlined trait that you can implement to create a pass; the
+/// pass will be named after the type, and it will consist of a main
+/// loop that goes over each available MIR and applies `run_pass`.
+pub trait MirPass<'tcx> {
+    const LEVEL: OptLevel;
+
+    fn name(&self) -> Cow<'_, str> {
+        let name = std::any::type_name::<Self>();
+        name.rsplit(':').next().unwrap().into()
+    }
+
+    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>);
+}
+
+const UNSOUND_MIR_OPT_LEVEL: u8 = 1;
+
+pub enum OptLevel {
+    /// Passes that will run at `-Zmir-opt-level=N` or higher.
+    N(u8),
+
+    /// Passes that are known or suspected to cause miscompilations.
+    ///
+    /// These passes only run if `-Zunsound-mir-opts` is enabled and we are at `mir-opt-level=1` or
+    /// above.
+    Unsound,
+
+    /// Passes that clean up the MIR after other transformations.
+    ///
+    /// A `Cleanup` pass is skipped if the pass immediately preceding it is skipped.
+    //
+    // FIXME: Maybe we want to run the cleanup unless *all* passes between it and the last cleanup
+    // were skipped?
+    Cleanup,
+}
+
+impl OptLevel {
+    /// A pass that will always run, regardless of `-Zmir-opt-level` or other flags.
+    pub const ALWAYS: Self = OptLevel::N(0);
+
+    /// A pass that will run if no flags are passed to `rustc` (e.g. `-Zmir-opt-level`).
+    pub const DEFAULT: Self = OptLevel::N(1);
+}
+
+/// RAII-style type that runs a series of optimization passes on a `Body`.
+///
+/// Upon going out of scope, this type updates the `MirPhase` of that `Body`.
+pub struct PassManager<'mir, 'tcx> {
+    tcx: TyCtxt<'tcx>,
+    body: &'mir mut Body<'tcx>,
+    phase_change: MirPhase,
+    passes_run: usize,
+    skip_cleanup: bool,
+}
+
+impl PassManager<'mir, 'tcx> {
+    pub fn new(tcx: TyCtxt<'tcx>, body: &'mir mut Body<'tcx>, phase_change: MirPhase) -> Self {
+        assert!(body.phase < phase_change);
+
+        let ret = PassManager { tcx, phase_change, body, passes_run: 0, skip_cleanup: false };
+
+        if tcx.sess.opts.debugging_opts.validate_mir {
+            ret.validate(&format!("input to phase {:?}", phase_change));
+        }
+
+        ret
+    }
+
+    fn is_pass_enabled<P>(&self, pass: &P) -> bool
+    where
+        P: MirPass<'tcx>,
+    {
+        let opts = &self.tcx.sess.opts.debugging_opts;
+        let level_required = match P::LEVEL {
+            OptLevel::Cleanup => return !self.skip_cleanup,
+            OptLevel::Unsound if !opts.unsound_mir_opts => return false,
+
+            OptLevel::Unsound => UNSOUND_MIR_OPT_LEVEL,
+            OptLevel::N(n) => n,
+        };
+
+        // Optimization passes that are not always run can be disabled
+        if level_required != 0 && is_skipped(&pass.name(), &opts.mir_opt_skip_pass) {
+            return false;
+        }
+
+        opts.mir_opt_level >= level_required.into()
+    }
+
+    pub fn validate(&self, when: &str) {
+        validate::validate_body(self.tcx, self.body, when);
+    }
+
+    pub fn run_pass<P>(&mut self, pass: &P)
+    where
+        P: MirPass<'tcx>,
+    {
+        if !self.is_pass_enabled(pass) {
+            info!("Skipping {}", pass.name());
+            self.skip_cleanup = true;
+            return;
+        }
+
+        dump_mir::on_mir_pass(
+            self.tcx,
+            &format_args!("{:03}-{:03}", self.body.phase.phase_index(), self.passes_run),
+            &pass.name(),
+            self.body,
+            false,
+        );
+        pass.run_pass(self.tcx, self.body);
+        dump_mir::on_mir_pass(
+            self.tcx,
+            &format_args!("{:03}-{:03}", self.body.phase.phase_index(), self.passes_run),
+            &pass.name(),
+            self.body,
+            true,
+        );
+
+        self.skip_cleanup = false;
+        self.passes_run += 1;
+
+        if self.tcx.sess.opts.debugging_opts.validate_mir {
+            self.validate(&format!(
+                "after {} while transitioning to {:?}",
+                pass.name(),
+                self.phase_change
+            ));
+        }
+    }
+}
+
+impl Drop for PassManager<'mir, 'tcx> {
+    fn drop(&mut self) {
+        self.body.phase = self.phase_change;
+
+        // Do MIR validation after all optimization passes have run regardless of `-Zvalidate_mir`.
+        if self.phase_change == MirPhase::Optimization {
+            self.validate(&format!("end of phase {:?}", self.phase_change));
+        }
+    }
+}
+
+macro_rules! run_passes {
+    ($manager:expr => [$($pass:expr),* $(,)?]) => {{
+        let ref mut manager: PassManager<'_, '_> = $manager;
+        $( manager.run_pass(&$pass); )*
+    }}
+}
+
+fn is_skipped(pass_name: &str, skipped_passes: &[String]) -> bool {
+    skipped_passes
+        .into_iter()
+        .filter(|skipped| !skipped.is_empty())
+        .any(|skipped| pass_name.starts_with(skipped))
+}
diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs
index 7abc998d3882f..21a3ca63e909e 100644
--- a/compiler/rustc_mir/src/transform/promote_consts.rs
+++ b/compiler/rustc_mir/src/transform/promote_consts.rs
@@ -32,7 +32,7 @@ use std::{cmp, iter, mem};
 
 use crate::const_eval::{is_const_fn, is_unstable_const_fn};
 use crate::transform::check_consts::{is_lang_panic_fn, qualifs, ConstCx};
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 
 /// A `MirPass` for promotion.
 ///
@@ -47,6 +47,8 @@ pub struct PromoteTemps<'tcx> {
 }
 
 impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         // There's not really any point in promoting errorful MIR.
         //
diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
index b45c533d2c002..da66ab0696083 100644
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
@@ -1,4 +1,4 @@
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use crate::util::patch::MirPatch;
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::*;
@@ -20,6 +20,8 @@ pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>)
 }
 
 impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         remove_noop_landing_pads(tcx, body);
     }
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
index aaf3ecab4dca7..ebc112b74ab33 100644
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
@@ -1,6 +1,6 @@
 //! This pass replaces a drop of a type that does not need dropping, with a goto
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{ParamEnv, TyCtxt};
@@ -10,6 +10,8 @@ use super::simplify::simplify_cfg;
 pub struct RemoveUnneededDrops;
 
 impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running RemoveUnneededDrops on {:?}", body.source);
         let mut opt_finder = RemoveUnneededDropsOptimizationFinder {
diff --git a/compiler/rustc_mir/src/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs
index 205f718d6e446..386eef6eb3a0c 100644
--- a/compiler/rustc_mir/src/transform/rustc_peek.rs
+++ b/compiler/rustc_mir/src/transform/rustc_peek.rs
@@ -5,7 +5,7 @@ use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_target::spec::abi::Abi;
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_index::bit_set::BitSet;
 use rustc_middle::mir::{self, Body, Local, Location};
 use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -22,6 +22,8 @@ use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor};
 pub struct SanityCheck;
 
 impl<'tcx> MirPass<'tcx> for SanityCheck {
+    const LEVEL: OptLevel = OptLevel::ALWAYS;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         use crate::dataflow::has_rustc_mir_with;
         let def_id = body.source.def_id();
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
index f0c87bcf513cd..69334b9f2b0f9 100644
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ b/compiler/rustc_mir/src/transform/simplify.rs
@@ -27,7 +27,7 @@
 //! naively generate still contains the `_a = ()` write in the unreachable block "after" the
 //! return.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_index::bit_set::BitSet;
 use rustc_index::vec::{Idx, IndexVec};
 use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
@@ -55,6 +55,8 @@ pub fn simplify_cfg(body: &mut Body<'_>) {
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyCfg {
+    const LEVEL: OptLevel = OptLevel::Cleanup;
+
     fn name(&self) -> Cow<'_, str> {
         Cow::Borrowed(&self.label)
     }
@@ -318,6 +320,8 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) {
 pub struct SimplifyLocals;
 
 impl<'tcx> MirPass<'tcx> for SimplifyLocals {
+    const LEVEL: OptLevel = OptLevel::N(1);
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("running SimplifyLocals on {:?}", body.source);
 
diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs
index 161856a38ee03..6f5230f305072 100644
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ b/compiler/rustc_mir/src/transform/simplify_branches.rs
@@ -1,6 +1,6 @@
 //! A pass that simplifies branches when their condition is known.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
 
@@ -17,6 +17,8 @@ impl SimplifyBranches {
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyBranches {
+    const LEVEL: OptLevel = OptLevel::Cleanup;
+
     fn name(&self) -> Cow<'_, str> {
         Cow::Borrowed(&self.label)
     }
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
index 9f837cf78a608..7aad8513403c3 100644
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
@@ -1,4 +1,4 @@
-use super::MirPass;
+use super::{MirPass, OptLevel};
 use rustc_middle::{
     mir::{
         interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
@@ -24,6 +24,8 @@ use rustc_middle::{
 pub struct SimplifyComparisonIntegral;
 
 impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
+    const LEVEL: OptLevel = OptLevel::N(2);
+
     fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
 
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
index a4e7a5a94533d..16ec3488520cb 100644
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ b/compiler/rustc_mir/src/transform/simplify_try.rs
@@ -9,7 +9,7 @@
 //!
 //! into just `x`.
 
-use crate::transform::{simplify, MirPass};
+use crate::transform::{simplify, MirPass, OptLevel};
 use itertools::Itertools as _;
 use rustc_index::{bit_set::BitSet, vec::IndexVec};
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
@@ -367,12 +367,10 @@ fn optimization_applies<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        // FIXME(77359): This optimization can result in unsoundness.
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
+    // FIXME(77359): This optimization can result in unsoundness.
+    const LEVEL: OptLevel = OptLevel::Unsound;
 
+    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let source = body.source;
         trace!("running SimplifyArmIdentity on {:?}", source);
 
@@ -530,6 +528,8 @@ fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarFiel
 pub struct SimplifyBranchSame;
 
 impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         trace!("Running SimplifyBranchSame on {:?}", body.source);
         let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
index 87906e83ed56c..bce6195ebfc76 100644
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
@@ -1,6 +1,6 @@
 //! A pass that eliminates branches on uninhabited enum variants.
 
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_data_structures::stable_set::FxHashSet;
 use rustc_middle::mir::{
     BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, TerminatorKind,
@@ -71,6 +71,8 @@ fn variant_discriminants<'tcx>(
 }
 
 impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
+    const LEVEL: OptLevel = OptLevel::DEFAULT;
+
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         if body.source.promoted.is_some() {
             return;
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs
index c6426a06ea155..de43641453105 100644
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs
@@ -3,7 +3,7 @@
 //! post-order traversal of the blocks.
 
 use crate::transform::simplify;
-use crate::transform::MirPass;
+use crate::transform::{MirPass, OptLevel};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
@@ -12,13 +12,11 @@ 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;
-        }
+    // 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.
+    const LEVEL: OptLevel = OptLevel::N(3);
 
+    fn run_pass<'tcx>(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         let mut unreachable_blocks = FxHashSet::default();
         let mut replacements = FxHashMap::default();
 
diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs
index cf51e86c5bc8f..4843d3aa8dc86 100644
--- a/compiler/rustc_mir/src/transform/validate.rs
+++ b/compiler/rustc_mir/src/transform/validate.rs
@@ -4,7 +4,6 @@ use crate::dataflow::impls::MaybeStorageLive;
 use crate::dataflow::{Analysis, ResultsCursor};
 use crate::util::storage::AlwaysLiveLocals;
 
-use super::MirPass;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{
     AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue,
@@ -13,38 +12,32 @@ use rustc_middle::mir::{
 use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
 use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt};
 
-#[derive(Copy, Clone, Debug)]
-enum EdgeKind {
-    Unwind,
-    Normal,
+pub fn validate_body(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, when: &str) {
+    validate_body_during_phase(tcx, body, body.phase, when);
 }
 
-pub struct Validator {
-    /// Describes at which point in the pipeline this validation is happening.
-    pub when: String,
-    /// The phase for which we are upholding the dialect. If the given phase forbids a specific
-    /// element, this validator will now emit errors if that specific element is encountered.
-    /// Note that phases that change the dialect cause all *following* phases to check the
-    /// invariants of the new dialect. A phase that changes dialects never checks the new invariants
-    /// itself.
-    pub mir_phase: MirPhase,
-}
+pub fn validate_body_during_phase(
+    tcx: TyCtxt<'tcx>,
+    body: &Body<'tcx>,
+    phase: MirPhase,
+    when: &str,
+) {
+    let def_id = body.source.def_id();
+    let param_env = tcx.param_env(def_id);
 
-impl<'tcx> MirPass<'tcx> for Validator {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = body.source.def_id();
-        let param_env = tcx.param_env(def_id);
-        let mir_phase = self.mir_phase;
+    let always_live_locals = AlwaysLiveLocals::new(body);
+    let storage_liveness = MaybeStorageLive::new(always_live_locals)
+        .into_engine(tcx, body)
+        .iterate_to_fixpoint()
+        .into_results_cursor(body);
 
-        let always_live_locals = AlwaysLiveLocals::new(body);
-        let storage_liveness = MaybeStorageLive::new(always_live_locals)
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint()
-            .into_results_cursor(body);
+    TypeChecker { when, body, tcx, param_env, mir_phase: phase, storage_liveness }.visit_body(body);
+}
 
-        TypeChecker { when: &self.when, body, tcx, param_env, mir_phase, storage_liveness }
-            .visit_body(body);
-    }
+#[derive(Copy, Clone, Debug)]
+enum EdgeKind {
+    Unwind,
+    Normal,
 }
 
 /// Returns whether the two types are equal up to lifetimes.
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index a106007c274d3..082028d95baea 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -959,6 +959,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
     mir_emit_retag: bool = (false, parse_bool, [TRACKED],
         "emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
         (default: no)"),
+    mir_opt_skip_pass: Vec<String> = (Vec::new(), parse_string_push, [TRACKED],
+        "MIR optimization passes that will not run (default: [])"),
     mir_opt_level: usize = (1, parse_uint, [TRACKED],
         "MIR optimization level (0-3; default: 1)"),
     mutable_noalias: bool = (false, parse_bool, [TRACKED],
diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
index 8aab2299d2651..dafb7ba70fd55 100644
--- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff
@@ -2,20 +2,20 @@
 + // MIR for `arg_src` after CopyPropagation
   
   fn arg_src(_1: i32) -> i32 {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:27:12: 27:17
-      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30
-      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:29:12: 29:17
+      let mut _0: i32;                     // return place in scope 0 at $DIR/copy_propagation_arg.rs:29:27: 29:30
+      let _2: i32;                         // in scope 0 at $DIR/copy_propagation_arg.rs:30:9: 30:10
       scope 1 {
-          debug y => _0;                   // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10
+          debug y => _0;                   // in scope 1 at $DIR/copy_propagation_arg.rs:30:9: 30:10
       }
   
       bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10
-          _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14
-          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12
-          nop;                             // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:30:9: 30:10
+          _0 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:30:13: 30:14
+          _1 = const 123_i32;              // scope 1 at $DIR/copy_propagation_arg.rs:31:5: 31:12
+          nop;                             // scope 1 at $DIR/copy_propagation_arg.rs:32:5: 32:6
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:33:1: 33:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:33:2: 33:2
       }
   }
   
diff --git a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff
index fb793e53ea8a7..ea0de091bd23d 100644
--- a/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg.bar.CopyPropagation.diff
@@ -2,27 +2,27 @@
 + // MIR for `bar` after CopyPropagation
   
   fn bar(_1: u8) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:15:8: 15:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:15:19: 15:19
-      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
-      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:17:8: 17:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:17:19: 17:19
+      let _2: u8;                          // in scope 0 at $DIR/copy_propagation_arg.rs:18:5: 18:13
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:18:11: 18:12
   
       bb0: {
-          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
-          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
-          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:16:11: 16:12
-          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:16:5: 16:13
+          StorageLive(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:18:5: 18:13
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:18:11: 18:12
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:18:11: 18:12
+          _2 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:18:5: 18:13
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:16:5: 16:10
+                                           // + span: $DIR/copy_propagation_arg.rs:18:5: 18:10
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:12: 16:13
-          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:16:13: 16:14
-          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:17:5: 17:10
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:15:19: 18:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:18:2: 18:2
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:18:12: 18:13
+          StorageDead(_2);                 // scope 0 at $DIR/copy_propagation_arg.rs:18:13: 18:14
+          _1 = const 5_u8;                 // scope 0 at $DIR/copy_propagation_arg.rs:19:5: 19:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:17:19: 20:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:20:2: 20:2
       }
   }
   
diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
index 1ea51fec71069..ad57f5555f380 100644
--- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff
@@ -2,17 +2,17 @@
 + // MIR for `baz` after CopyPropagation
   
   fn baz(_1: i32) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:21:8: 21:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:21:20: 21:20
-      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:23:8: 23:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:23:20: 23:20
+      let mut _2: i32;                     // in scope 0 at $DIR/copy_propagation_arg.rs:25:9: 25:10
   
       bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:25:9: 25:10
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:25:9: 25:10
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:25:5: 25:10
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:25:9: 25:10
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:23:20: 26:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:26:2: 26:2
       }
   }
   
diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
index 48ab37a239c62..bd05f75f8ba9a 100644
--- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
+++ b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff
@@ -2,27 +2,27 @@
 + // MIR for `foo` after CopyPropagation
   
   fn foo(_1: u8) -> () {
-      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:9:8: 9:13
-      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:9:19: 9:19
-      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
-      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
+      debug x => _1;                       // in scope 0 at $DIR/copy_propagation_arg.rs:11:8: 11:13
+      let mut _0: ();                      // return place in scope 0 at $DIR/copy_propagation_arg.rs:11:19: 11:19
+      let mut _2: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:13:9: 13:17
+      let mut _3: u8;                      // in scope 0 at $DIR/copy_propagation_arg.rs:13:15: 13:16
   
       bb0: {
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
-          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
-          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16
-          _1 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:13:9: 13:17
+          StorageLive(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:13:15: 13:16
+          _3 = _1;                         // scope 0 at $DIR/copy_propagation_arg.rs:13:15: 13:16
+          _1 = dummy(move _3) -> bb1;      // scope 0 at $DIR/copy_propagation_arg.rs:13:9: 13:17
                                            // mir::Constant
-                                           // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14
+                                           // + span: $DIR/copy_propagation_arg.rs:13:9: 13:14
                                            // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar(<ZST>)) }
       }
   
       bb1: {
-          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17
-          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17
-          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2
-          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2
+          StorageDead(_3);                 // scope 0 at $DIR/copy_propagation_arg.rs:13:16: 13:17
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:13:5: 13:17
+          nop;                             // scope 0 at $DIR/copy_propagation_arg.rs:13:16: 13:17
+          _0 = const ();                   // scope 0 at $DIR/copy_propagation_arg.rs:11:19: 14:2
+          return;                          // scope 0 at $DIR/copy_propagation_arg.rs:14:2: 14:2
       }
   }
   
diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs
index 3a00fc58a4ea8..6dca1aed3e356 100644
--- a/src/test/mir-opt/copy_propagation_arg.rs
+++ b/src/test/mir-opt/copy_propagation_arg.rs
@@ -1,3 +1,5 @@
+// compile-flags: -Z unsound-mir-opts
+
 // Check that CopyPropagation does not propagate an assignment to a function argument
 // (doing so can break usages of the original argument value)
 
diff --git a/src/test/mir-opt/issue-73223.rs b/src/test/mir-opt/issue-73223.rs
index 703b876123133..954ad4b102110 100644
--- a/src/test/mir-opt/issue-73223.rs
+++ b/src/test/mir-opt/issue-73223.rs
@@ -1,3 +1,5 @@
+// compile-flags: -Z unsound-mir-opts -Z mir-opt-skip-pass=CopyProp
+
 fn main() {
     let split = match Some(1) {
         Some(v) => v,
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
index ef7c73068faf6..2971634c4ec6e 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff
@@ -2,10 +2,10 @@
 + // MIR for `main` after PreCodegen
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:5:14: 5:15
       let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -23,10 +23,10 @@
       let mut _21: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       let mut _22: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:4:9: 4:14
+          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:9:9: 9:14
           scope 3 {
-              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:9:9: 9:14
               let _7: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               scope 4 {
@@ -61,7 +61,7 @@
           }
       }
       scope 2 {
-          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:5:14: 5:15
       }
       scope 7 {
       }
@@ -69,17 +69,17 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_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
-          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
           (_5.0: &i32) = &_1;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _6 = const main::promoted[1];    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
@@ -108,9 +108,9 @@
           StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:3:11: 11:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb2: {
diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
index ef7c73068faf6..2971634c4ec6e 100644
--- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff
@@ -2,10 +2,10 @@
 + // MIR for `main` after PreCodegen
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+      let _3: i32;                         // in scope 0 at $DIR/issue-73223.rs:5:14: 5:15
       let mut _5: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _6: &i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _9: bool;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -23,10 +23,10 @@
       let mut _21: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       let mut _22: std::fmt::ArgumentV1;   // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL
       scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:4:9: 4:14
+          let _4: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:9:9: 9:14
           scope 3 {
-              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              debug _prev => _4;           // in scope 3 at $DIR/issue-73223.rs:9:9: 9:14
               let _7: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let _8: &i32;                // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               scope 4 {
@@ -61,7 +61,7 @@
           }
       }
       scope 2 {
-          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _3;                   // in scope 2 at $DIR/issue-73223.rs:5:14: 5:15
       }
       scope 7 {
       }
@@ -69,17 +69,17 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_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
-          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          StorageLive(_3);                 // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _3 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _1 = _3;                         // scope 2 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_3);                 // scope 0 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          ((_4 as Some).0: i32) = _1;      // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          discriminant(_4) = 1;            // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
           (_5.0: &i32) = &_1;              // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           _6 = const main::promoted[1];    // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
                                            // ty::Const
@@ -108,9 +108,9 @@
           StorageDead(_9);                 // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_7);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:3:11: 11:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb2: {
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
index 9039735f6ba38..85115c5b3c7ec 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff
@@ -2,18 +2,18 @@
 + // MIR for `main` after SimplifyArmIdentity
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:3:9: 3:16
-      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:4:17: 4:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:5:9: 5:16
+      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:6:17: 6:23
+      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:9:22: 9:27
       let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:8:23: 8:24
+      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:10:23: 10:24
       let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -42,10 +42,10 @@
       let mut _42: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:4:9: 4:14
+          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:9:9: 9:14
           scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:9:9: 9:14
               let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let mut _45: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -86,7 +86,7 @@
           }
       }
       scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:5:14: 5:15
       }
       scope 7 {
       }
@@ -94,33 +94,33 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_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
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:5:9: 5:16
+          goto -> bb2;                     // scope 0 at $DIR/issue-73223.rs:5:9: 5:16
       }
   
       bb1: {
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:6:17: 6:23
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb2: {
-          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
-          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
+          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:9:9: 9:14
+          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
+          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
+          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:9:27: 9:28
           StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -163,10 +163,10 @@
           StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:3:11: 11:2
+          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:11:1: 11:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb4: {
diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
index 9039735f6ba38..85115c5b3c7ec 100644
--- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
+++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff
@@ -2,18 +2,18 @@
 + // MIR for `main` after SimplifyArmIdentity
   
   fn main() -> () {
-      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11
-      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:3:9: 3:16
-      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15
-      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:4:17: 4:23
-      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27
+      let mut _0: ();                      // return place in scope 0 at $DIR/issue-73223.rs:3:11: 3:11
+      let _1: i32;                         // in scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+      let mut _2: std::option::Option<i32>; // in scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+      let mut _3: isize;                   // in scope 0 at $DIR/issue-73223.rs:5:9: 5:16
+      let _4: i32;                         // in scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+      let mut _5: !;                       // in scope 0 at $DIR/issue-73223.rs:6:17: 6:23
+      let mut _7: i32;                     // in scope 0 at $DIR/issue-73223.rs:9:22: 9:27
       let _8: ();                          // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _9: (&i32, &i32);            // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _10: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _11: &i32;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:8:23: 8:24
+      let _12: i32;                        // in scope 0 at $DIR/issue-73223.rs:10:23: 10:24
       let mut _15: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _16: bool;                   // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _17: i32;                    // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -42,10 +42,10 @@
       let mut _42: &&i32;                  // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       let mut _43: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
       scope 1 {
-          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14
-          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14
+          debug split => _1;               // in scope 1 at $DIR/issue-73223.rs:4:9: 4:14
+          let _6: std::option::Option<i32>; // in scope 1 at $DIR/issue-73223.rs:9:9: 9:14
           scope 3 {
-              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14
+              debug _prev => _6;           // in scope 3 at $DIR/issue-73223.rs:9:9: 9:14
               let _13: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let _14: &i32;               // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
               let mut _45: &i32;           // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -86,7 +86,7 @@
           }
       }
       scope 2 {
-          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15
+          debug v => _4;                   // in scope 2 at $DIR/issue-73223.rs:5:14: 5:15
       }
       scope 7 {
       }
@@ -94,33 +94,33 @@
       }
   
       bb0: {
-          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:2:9: 2:14
-          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:2:23: 2:30
-          ((_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
+          StorageLive(_1);                 // scope 0 at $DIR/issue-73223.rs:4:9: 4:14
+          StorageLive(_2);                 // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          discriminant(_2) = 1;            // scope 0 at $DIR/issue-73223.rs:4:23: 4:30
+          _3 = const 1_isize;              // scope 0 at $DIR/issue-73223.rs:5:9: 5:16
+          goto -> bb2;                     // scope 0 at $DIR/issue-73223.rs:5:9: 5:16
       }
   
       bb1: {
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:4:17: 4:23
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:6:17: 6:23
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb2: {
-          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
-          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:3:20: 3:21
-          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:5:6: 5:7
-          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:7:9: 7:14
-          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:7:22: 7:27
-          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:7:17: 7:28
-          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:7:27: 7:28
+          StorageLive(_4);                 // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _4 = ((_2 as Some).0: i32);      // scope 0 at $DIR/issue-73223.rs:5:14: 5:15
+          _1 = _4;                         // scope 2 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_4);                 // scope 0 at $DIR/issue-73223.rs:5:20: 5:21
+          StorageDead(_2);                 // scope 0 at $DIR/issue-73223.rs:7:6: 7:7
+          StorageLive(_6);                 // scope 1 at $DIR/issue-73223.rs:9:9: 9:14
+          StorageLive(_7);                 // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          _7 = _1;                         // scope 1 at $DIR/issue-73223.rs:9:22: 9:27
+          ((_6 as Some).0: i32) = move _7; // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
+          discriminant(_6) = 1;            // scope 1 at $DIR/issue-73223.rs:9:17: 9:28
+          StorageDead(_7);                 // scope 1 at $DIR/issue-73223.rs:9:27: 9:28
           StorageLive(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageLive(_10);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
@@ -163,10 +163,10 @@
           StorageDead(_13);                // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_9);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
           StorageDead(_8);                 // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL
-          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:1:11: 9:2
-          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:9:1: 9:2
-          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:9:1: 9:2
-          return;                          // scope 0 at $DIR/issue-73223.rs:9:2: 9:2
+          _0 = const ();                   // scope 0 at $DIR/issue-73223.rs:3:11: 11:2
+          StorageDead(_6);                 // scope 1 at $DIR/issue-73223.rs:11:1: 11:2
+          StorageDead(_1);                 // scope 0 at $DIR/issue-73223.rs:11:1: 11:2
+          return;                          // scope 0 at $DIR/issue-73223.rs:11:2: 11:2
       }
   
       bb4: {
diff --git a/src/test/mir-opt/simplify-arm-identity.rs b/src/test/mir-opt/simplify-arm-identity.rs
index 0a59032e87ba0..b9072a7dc14bd 100644
--- a/src/test/mir-opt/simplify-arm-identity.rs
+++ b/src/test/mir-opt/simplify-arm-identity.rs
@@ -1,7 +1,7 @@
 // Checks that `SimplifyArmIdentity` is not applied if enums have incompatible layouts.
 // Regression test for issue #66856.
 //
-// compile-flags: -Zmir-opt-level=2
+// compile-flags: -Zmir-opt-level=2 -Zunsound-mir-opts
 // EMIT_MIR_FOR_EACH_BIT_WIDTH
 
 enum Src {