about summary refs log tree commit diff
path: root/compiler/rustc_mir/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir/src')
-rw-r--r--compiler/rustc_mir/src/dataflow/drop_flag_effects.rs10
-rw-r--r--compiler/rustc_mir/src/dataflow/mod.rs8
-rw-r--r--compiler/rustc_mir/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_mir/src/interpret/operand.rs6
-rw-r--r--compiler/rustc_mir/src/interpret/step.rs2
-rw-r--r--compiler/rustc_mir/src/lib.rs5
-rw-r--r--compiler/rustc_mir/src/shim.rs946
-rw-r--r--compiler/rustc_mir/src/transform/abort_unwinding_calls.rs141
-rw-r--r--compiler/rustc_mir/src/transform/add_call_guards.rs86
-rw-r--r--compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs108
-rw-r--r--compiler/rustc_mir/src/transform/add_retag.rs186
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs157
-rw-r--r--compiler/rustc_mir/src/transform/check_packed_ref.rs115
-rw-r--r--compiler/rustc_mir/src/transform/check_unsafety.rs574
-rw-r--r--compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs59
-rw-r--r--compiler/rustc_mir/src/transform/const_debuginfo.rs102
-rw-r--r--compiler/rustc_mir/src/transform/const_goto.rs122
-rw-r--r--compiler/rustc_mir/src/transform/const_prop.rs1312
-rw-r--r--compiler/rustc_mir/src/transform/coverage/counters.rs614
-rw-r--r--compiler/rustc_mir/src/transform/coverage/debug.rs840
-rw-r--r--compiler/rustc_mir/src/transform/coverage/graph.rs769
-rw-r--r--compiler/rustc_mir/src/transform/coverage/mod.rs588
-rw-r--r--compiler/rustc_mir/src/transform/coverage/query.rs191
-rw-r--r--compiler/rustc_mir/src/transform/coverage/spans.rs900
-rw-r--r--compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml8
-rw-r--r--compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs6
-rw-r--r--compiler/rustc_mir/src/transform/coverage/tests.rs721
-rw-r--r--compiler/rustc_mir/src/transform/deaggregator.rs49
-rw-r--r--compiler/rustc_mir/src/transform/deduplicate_blocks.rs189
-rw-r--r--compiler/rustc_mir/src/transform/dest_prop.rs1039
-rw-r--r--compiler/rustc_mir/src/transform/dump_mir.rs59
-rw-r--r--compiler/rustc_mir/src/transform/early_otherwise_branch.rs369
-rw-r--r--compiler/rustc_mir/src/transform/elaborate_drops.rs589
-rw-r--r--compiler/rustc_mir/src/transform/function_item_references.rs223
-rw-r--r--compiler/rustc_mir/src/transform/generator.rs1500
-rw-r--r--compiler/rustc_mir/src/transform/inline.rs966
-rw-r--r--compiler/rustc_mir/src/transform/inline/cycle.rs169
-rw-r--r--compiler/rustc_mir/src/transform/instcombine.rs131
-rw-r--r--compiler/rustc_mir/src/transform/lower_intrinsics.rs154
-rw-r--r--compiler/rustc_mir/src/transform/lower_slice_len.rs100
-rw-r--r--compiler/rustc_mir/src/transform/match_branches.rs176
-rw-r--r--compiler/rustc_mir/src/transform/mod.rs605
-rw-r--r--compiler/rustc_mir/src/transform/multiple_return_terminators.rs43
-rw-r--r--compiler/rustc_mir/src/transform/nrvo.rs239
-rw-r--r--compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs133
-rw-r--r--compiler/rustc_mir/src/transform/remove_storage_markers.rs25
-rw-r--r--compiler/rustc_mir/src/transform/remove_unneeded_drops.rs42
-rw-r--r--compiler/rustc_mir/src/transform/remove_zsts.rs76
-rw-r--r--compiler/rustc_mir/src/transform/required_consts.rs23
-rw-r--r--compiler/rustc_mir/src/transform/separate_const_switch.rs343
-rw-r--r--compiler/rustc_mir/src/transform/simplify.rs592
-rw-r--r--compiler/rustc_mir/src/transform/simplify_branches.rs66
-rw-r--r--compiler/rustc_mir/src/transform/simplify_comparison_integral.rs238
-rw-r--r--compiler/rustc_mir/src/transform/simplify_try.rs795
-rw-r--r--compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs117
-rw-r--r--compiler/rustc_mir/src/transform/unreachable_prop.rs112
-rw-r--r--compiler/rustc_mir/src/util/mod.rs4
-rw-r--r--compiler/rustc_mir/src/util/pretty.rs2
58 files changed, 21 insertions, 17725 deletions
diff --git a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
index d4f8f994ae9..fa449a23688 100644
--- a/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
+++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs
@@ -79,7 +79,7 @@ fn place_contents_drop_state_cannot_differ<'tcx>(
     }
 }
 
-pub(crate) fn on_lookup_result_bits<'tcx, F>(
+pub fn on_lookup_result_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
@@ -96,7 +96,7 @@ pub(crate) fn on_lookup_result_bits<'tcx, F>(
     }
 }
 
-pub(crate) fn on_all_children_bits<'tcx, F>(
+pub fn on_all_children_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     move_data: &MoveData<'tcx>,
@@ -138,7 +138,7 @@ pub(crate) fn on_all_children_bits<'tcx, F>(
     on_all_children_bits(tcx, body, move_data, move_path_index, &mut each_child);
 }
 
-pub(crate) fn on_all_drop_children_bits<'tcx, F>(
+pub fn on_all_drop_children_bits<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
@@ -161,7 +161,7 @@ pub(crate) fn on_all_drop_children_bits<'tcx, F>(
     })
 }
 
-pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
+pub fn drop_flag_effects_for_function_entry<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
@@ -179,7 +179,7 @@ pub(crate) fn drop_flag_effects_for_function_entry<'tcx, F>(
     }
 }
 
-pub(crate) fn drop_flag_effects_for_location<'tcx, F>(
+pub fn drop_flag_effects_for_location<'tcx, F>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
     ctxt: &MoveDataParamEnv<'tcx>,
diff --git a/compiler/rustc_mir/src/dataflow/mod.rs b/compiler/rustc_mir/src/dataflow/mod.rs
index bb38f90a3ba..f388d41d317 100644
--- a/compiler/rustc_mir/src/dataflow/mod.rs
+++ b/compiler/rustc_mir/src/dataflow/mod.rs
@@ -3,7 +3,11 @@ use rustc_middle::ty;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
 
-pub(crate) use self::drop_flag_effects::*;
+pub use self::drop_flag_effects::{
+    drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
+    move_path_children_matching, on_all_children_bits, on_all_drop_children_bits,
+    on_lookup_result_bits,
+};
 pub use self::framework::{
     fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine, Forward,
     GenKill, GenKillAnalysis, JoinSemiLattice, Results, ResultsCursor, ResultsRefCursor,
@@ -26,7 +30,7 @@ pub struct MoveDataParamEnv<'tcx> {
     pub param_env: ty::ParamEnv<'tcx>,
 }
 
-pub(crate) fn has_rustc_mir_with(
+pub fn has_rustc_mir_with(
     _sess: &Session,
     attrs: &[ast::Attribute],
     name: Symbol,
diff --git a/compiler/rustc_mir/src/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs
index f2457d11d9e..84e79408397 100644
--- a/compiler/rustc_mir/src/interpret/intern.rs
+++ b/compiler/rustc_mir/src/interpret/intern.rs
@@ -420,7 +420,7 @@ impl<'mir, 'tcx: 'mir, M: super::intern::CompileTimeMachine<'mir, 'tcx, !>>
     /// A helper function that allocates memory for the layout given and gives you access to mutate
     /// it. Once your own mutation code is done, the backing `Allocation` is removed from the
     /// current `Memory` and returned.
-    pub(crate) fn intern_with_temp_alloc(
+    pub fn intern_with_temp_alloc(
         &mut self,
         layout: TyAndLayout<'tcx>,
         f: impl FnOnce(
diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs
index e67a6690836..63aca67c944 100644
--- a/compiler/rustc_mir/src/interpret/operand.rs
+++ b/compiler/rustc_mir/src/interpret/operand.rs
@@ -296,7 +296,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Note that for a given layout, this operation will either always fail or always
     /// succeed!  Whether it succeeds depends on whether the layout can be represented
     /// in an `Immediate`, not on which data is stored there currently.
-    pub(crate) fn try_read_immediate(
+    pub fn try_read_immediate(
         &self,
         src: &OpTy<'tcx, M::PointerTag>,
     ) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
@@ -547,7 +547,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     // in patterns via the `const_eval` module
     /// The `val` and `layout` are assumed to already be in our interpreter
     /// "universe" (param_env).
-    crate fn const_to_op(
+    pub fn const_to_op(
         &self,
         val: &ty::Const<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
@@ -566,7 +566,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
         }
     }
 
-    crate fn mir_const_to_op(
+    pub fn mir_const_to_op(
         &self,
         val: &mir::ConstantKind<'tcx>,
         layout: Option<TyAndLayout<'tcx>>,
diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs
index 1e96581c392..09bd07660a3 100644
--- a/compiler/rustc_mir/src/interpret/step.rs
+++ b/compiler/rustc_mir/src/interpret/step.rs
@@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
 
     /// Runs the interpretation logic for the given `mir::Statement` at the current frame and
     /// statement counter. This also moves the statement counter forward.
-    crate fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
+    pub fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> InterpResult<'tcx> {
         info!("{:?}", stmt);
 
         use rustc_middle::mir::StatementKind::*;
diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs
index 16dddc949df..4c79c7da15c 100644
--- a/compiler/rustc_mir/src/lib.rs
+++ b/compiler/rustc_mir/src/lib.rs
@@ -37,7 +37,6 @@ pub mod const_eval;
 pub mod dataflow;
 pub mod interpret;
 pub mod monomorphize;
-mod shim;
 pub mod transform;
 pub mod util;
 
@@ -45,15 +44,11 @@ use rustc_middle::ty::query::Providers;
 
 pub fn provide(providers: &mut Providers) {
     const_eval::provide(providers);
-    shim::provide(providers);
-    transform::provide(providers);
     monomorphize::partitioning::provide(providers);
     monomorphize::polymorphize::provide(providers);
     providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
     providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
     providers.const_caller_location = const_eval::const_caller_location;
-    providers.mir_callgraph_reachable = transform::inline::cycle::mir_callgraph_reachable;
-    providers.mir_inliner_callees = transform::inline::cycle::mir_inliner_callees;
     providers.destructure_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
         const_eval::destructure_const(tcx, param_env, value)
diff --git a/compiler/rustc_mir/src/shim.rs b/compiler/rustc_mir/src/shim.rs
deleted file mode 100644
index 8083ec95447..00000000000
--- a/compiler/rustc_mir/src/shim.rs
+++ /dev/null
@@ -1,946 +0,0 @@
-use rustc_hir as hir;
-use rustc_hir::def_id::DefId;
-use rustc_hir::lang_items::LangItem;
-use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
-
-use rustc_index::vec::{Idx, IndexVec};
-
-use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
-
-use std::fmt;
-use std::iter;
-
-use crate::transform::{
-    abort_unwinding_calls, add_call_guards, add_moves_for_packed_drops, remove_noop_landing_pads,
-    run_passes, simplify,
-};
-use crate::util::elaborate_drops::{self, DropElaborator, DropFlagMode, DropStyle};
-use crate::util::expand_aggregate;
-use crate::util::patch::MirPatch;
-
-pub fn provide(providers: &mut Providers) {
-    providers.mir_shims = make_shim;
-}
-
-fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> {
-    debug!("make_shim({:?})", instance);
-
-    let mut result = match instance {
-        ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance),
-        ty::InstanceDef::VtableShim(def_id) => {
-            build_call_shim(tcx, instance, Some(Adjustment::Deref), CallKind::Direct(def_id))
-        }
-        ty::InstanceDef::FnPtrShim(def_id, ty) => {
-            let trait_ = tcx.trait_of_item(def_id).unwrap();
-            let adjustment = match tcx.fn_trait_kind_from_lang_item(trait_) {
-                Some(ty::ClosureKind::FnOnce) => Adjustment::Identity,
-                Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref,
-                None => bug!("fn pointer {:?} is not an fn", ty),
-            };
-
-            build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty))
-        }
-        // We are generating a call back to our def-id, which the
-        // codegen backend knows to turn to an actual call, be it
-        // a virtual call, or a direct call to a function for which
-        // indirect calls must be codegen'd differently than direct ones
-        // (such as `#[track_caller]`).
-        ty::InstanceDef::ReifyShim(def_id) => {
-            build_call_shim(tcx, instance, None, CallKind::Direct(def_id))
-        }
-        ty::InstanceDef::ClosureOnceShim { call_once: _ } => {
-            let fn_mut = tcx.require_lang_item(LangItem::FnMut, None);
-            let call_mut = tcx
-                .associated_items(fn_mut)
-                .in_definition_order()
-                .find(|it| it.kind == ty::AssocKind::Fn)
-                .unwrap()
-                .def_id;
-
-            build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
-        }
-        ty::InstanceDef::DropGlue(def_id, ty) => build_drop_shim(tcx, def_id, ty),
-        ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty),
-        ty::InstanceDef::Virtual(..) => {
-            bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance)
-        }
-        ty::InstanceDef::Intrinsic(_) => {
-            bug!("creating shims from intrinsics ({:?}) is unsupported", instance)
-        }
-    };
-    debug!("make_shim({:?}) = untransformed {:?}", instance, result);
-
-    run_passes(
-        tcx,
-        &mut result,
-        MirPhase::Const,
-        &[&[
-            &add_moves_for_packed_drops::AddMovesForPackedDrops,
-            &remove_noop_landing_pads::RemoveNoopLandingPads,
-            &simplify::SimplifyCfg::new("make_shim"),
-            &add_call_guards::CriticalCallEdges,
-            &abort_unwinding_calls::AbortUnwindingCalls,
-        ]],
-    );
-
-    debug!("make_shim({:?}) = {:?}", instance, result);
-
-    result
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum Adjustment {
-    /// Pass the receiver as-is.
-    Identity,
-
-    /// We get passed `&[mut] self` and call the target with `*self`.
-    ///
-    /// This either copies `self` (if `Self: Copy`, eg. for function items), or moves out of it
-    /// (for `VtableShim`, which effectively is passed `&own Self`).
-    Deref,
-
-    /// We get passed `self: Self` and call the target with `&mut self`.
-    ///
-    /// In this case we need to ensure that the `Self` is dropped after the call, as the callee
-    /// won't do it for us.
-    RefMut,
-}
-
-#[derive(Copy, Clone, Debug, PartialEq)]
-enum CallKind<'tcx> {
-    /// Call the `FnPtr` that was passed as the receiver.
-    Indirect(Ty<'tcx>),
-
-    /// Call a known `FnDef`.
-    Direct(DefId),
-}
-
-fn local_decls_for_sig<'tcx>(
-    sig: &ty::FnSig<'tcx>,
-    span: Span,
-) -> IndexVec<Local, LocalDecl<'tcx>> {
-    iter::once(LocalDecl::new(sig.output(), span))
-        .chain(sig.inputs().iter().map(|ity| LocalDecl::new(ity, span).immutable()))
-        .collect()
-}
-
-fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option<Ty<'tcx>>) -> Body<'tcx> {
-    debug!("build_drop_shim(def_id={:?}, ty={:?})", def_id, ty);
-
-    // Check if this is a generator, if so, return the drop glue for it
-    if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) {
-        let body = tcx.optimized_mir(gen_def_id).generator_drop().unwrap();
-        return body.clone().subst(tcx, substs);
-    }
-
-    let substs = if let Some(ty) = ty {
-        tcx.intern_substs(&[ty.into()])
-    } else {
-        InternalSubsts::identity_for_item(tcx, def_id)
-    };
-    let sig = tcx.fn_sig(def_id).subst(tcx, substs);
-    let sig = tcx.erase_late_bound_regions(sig);
-    let span = tcx.def_span(def_id);
-
-    let source_info = SourceInfo::outermost(span);
-
-    let return_block = BasicBlock::new(1);
-    let mut blocks = IndexVec::with_capacity(2);
-    let block = |blocks: &mut IndexVec<_, _>, kind| {
-        blocks.push(BasicBlockData {
-            statements: vec![],
-            terminator: Some(Terminator { source_info, kind }),
-            is_cleanup: false,
-        })
-    };
-    block(&mut blocks, TerminatorKind::Goto { target: return_block });
-    block(&mut blocks, TerminatorKind::Return);
-
-    let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty));
-    let mut body =
-        new_body(tcx, source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span);
-
-    if ty.is_some() {
-        // The first argument (index 0), but add 1 for the return value.
-        let dropee_ptr = Place::from(Local::new(1 + 0));
-        if tcx.sess.opts.debugging_opts.mir_emit_retag {
-            // Function arguments should be retagged, and we make this one raw.
-            body.basic_blocks_mut()[START_BLOCK].statements.insert(
-                0,
-                Statement {
-                    source_info,
-                    kind: StatementKind::Retag(RetagKind::Raw, Box::new(dropee_ptr)),
-                },
-            );
-        }
-        let patch = {
-            let param_env = tcx.param_env_reveal_all_normalized(def_id);
-            let mut elaborator =
-                DropShimElaborator { body: &body, patch: MirPatch::new(&body), tcx, param_env };
-            let dropee = tcx.mk_place_deref(dropee_ptr);
-            let resume_block = elaborator.patch.resume_block();
-            elaborate_drops::elaborate_drop(
-                &mut elaborator,
-                source_info,
-                dropee,
-                (),
-                return_block,
-                elaborate_drops::Unwind::To(resume_block),
-                START_BLOCK,
-            );
-            elaborator.patch
-        };
-        patch.apply(&mut body);
-    }
-
-    body
-}
-
-fn new_body<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    source: MirSource<'tcx>,
-    basic_blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
-    arg_count: usize,
-    span: Span,
-) -> Body<'tcx> {
-    Body::new(
-        tcx,
-        source,
-        basic_blocks,
-        IndexVec::from_elem_n(
-            SourceScopeData {
-                span,
-                parent_scope: None,
-                inlined: None,
-                inlined_parent_scope: None,
-                local_data: ClearCrossCrate::Clear,
-            },
-            1,
-        ),
-        local_decls,
-        IndexVec::new(),
-        arg_count,
-        vec![],
-        span,
-        None,
-    )
-}
-
-pub struct DropShimElaborator<'a, 'tcx> {
-    pub body: &'a Body<'tcx>,
-    pub patch: MirPatch<'tcx>,
-    pub tcx: TyCtxt<'tcx>,
-    pub param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'a, 'tcx> fmt::Debug for DropShimElaborator<'a, 'tcx> {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
-        Ok(())
-    }
-}
-
-impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> {
-    type Path = ();
-
-    fn patch(&mut self) -> &mut MirPatch<'tcx> {
-        &mut self.patch
-    }
-    fn body(&self) -> &'a Body<'tcx> {
-        self.body
-    }
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-
-    fn drop_style(&self, _path: Self::Path, mode: DropFlagMode) -> DropStyle {
-        match mode {
-            DropFlagMode::Shallow => {
-                // Drops for the contained fields are "shallow" and "static" - they will simply call
-                // the field's own drop glue.
-                DropStyle::Static
-            }
-            DropFlagMode::Deep => {
-                // The top-level drop is "deep" and "open" - it will be elaborated to a drop ladder
-                // dropping each field contained in the value.
-                DropStyle::Open
-            }
-        }
-    }
-
-    fn get_drop_flag(&mut self, _path: Self::Path) -> Option<Operand<'tcx>> {
-        None
-    }
-
-    fn clear_drop_flag(&mut self, _location: Location, _path: Self::Path, _mode: DropFlagMode) {}
-
-    fn field_subpath(&self, _path: Self::Path, _field: Field) -> Option<Self::Path> {
-        None
-    }
-    fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
-        None
-    }
-    fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option<Self::Path> {
-        Some(())
-    }
-    fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option<Self::Path> {
-        None
-    }
-}
-
-/// Builds a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
-fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
-    debug!("build_clone_shim(def_id={:?})", def_id);
-
-    let param_env = tcx.param_env(def_id);
-
-    let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
-    let is_copy = self_ty.is_copy_modulo_regions(tcx.at(builder.span), param_env);
-
-    let dest = Place::return_place();
-    let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
-
-    match self_ty.kind() {
-        _ if is_copy => builder.copy_shim(),
-        ty::Array(ty, len) => builder.array_shim(dest, src, ty, len),
-        ty::Closure(_, substs) => {
-            builder.tuple_like_shim(dest, src, substs.as_closure().upvar_tys())
-        }
-        ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
-        _ => bug!("clone shim for `{:?}` which is not `Copy` and is not an aggregate", self_ty),
-    };
-
-    builder.into_mir()
-}
-
-struct CloneShimBuilder<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
-    blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    span: Span,
-    sig: ty::FnSig<'tcx>,
-}
-
-impl CloneShimBuilder<'tcx> {
-    fn new(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Self {
-        // we must subst the self_ty because it's
-        // otherwise going to be TySelf and we can't index
-        // or access fields of a Place of type TySelf.
-        let substs = tcx.mk_substs_trait(self_ty, &[]);
-        let sig = tcx.fn_sig(def_id).subst(tcx, substs);
-        let sig = tcx.erase_late_bound_regions(sig);
-        let span = tcx.def_span(def_id);
-
-        CloneShimBuilder {
-            tcx,
-            def_id,
-            local_decls: local_decls_for_sig(&sig, span),
-            blocks: IndexVec::new(),
-            span,
-            sig,
-        }
-    }
-
-    fn into_mir(self) -> Body<'tcx> {
-        let source = MirSource::from_instance(ty::InstanceDef::CloneShim(
-            self.def_id,
-            self.sig.inputs_and_output[0],
-        ));
-        new_body(
-            self.tcx,
-            source,
-            self.blocks,
-            self.local_decls,
-            self.sig.inputs().len(),
-            self.span,
-        )
-    }
-
-    fn source_info(&self) -> SourceInfo {
-        SourceInfo::outermost(self.span)
-    }
-
-    fn block(
-        &mut self,
-        statements: Vec<Statement<'tcx>>,
-        kind: TerminatorKind<'tcx>,
-        is_cleanup: bool,
-    ) -> BasicBlock {
-        let source_info = self.source_info();
-        self.blocks.push(BasicBlockData {
-            statements,
-            terminator: Some(Terminator { source_info, kind }),
-            is_cleanup,
-        })
-    }
-
-    /// Gives the index of an upcoming BasicBlock, with an offset.
-    /// offset=0 will give you the index of the next BasicBlock,
-    /// offset=1 will give the index of the next-to-next block,
-    /// offset=-1 will give you the index of the last-created block
-    fn block_index_offset(&mut self, offset: usize) -> BasicBlock {
-        BasicBlock::new(self.blocks.len() + offset)
-    }
-
-    fn make_statement(&self, kind: StatementKind<'tcx>) -> Statement<'tcx> {
-        Statement { source_info: self.source_info(), kind }
-    }
-
-    fn copy_shim(&mut self) {
-        let rcvr = self.tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
-        let ret_statement = self.make_statement(StatementKind::Assign(Box::new((
-            Place::return_place(),
-            Rvalue::Use(Operand::Copy(rcvr)),
-        ))));
-        self.block(vec![ret_statement], TerminatorKind::Return, false);
-    }
-
-    fn make_place(&mut self, mutability: Mutability, ty: Ty<'tcx>) -> Place<'tcx> {
-        let span = self.span;
-        let mut local = LocalDecl::new(ty, span);
-        if mutability == Mutability::Not {
-            local = local.immutable();
-        }
-        Place::from(self.local_decls.push(local))
-    }
-
-    fn make_clone_call(
-        &mut self,
-        dest: Place<'tcx>,
-        src: Place<'tcx>,
-        ty: Ty<'tcx>,
-        next: BasicBlock,
-        cleanup: BasicBlock,
-    ) {
-        let tcx = self.tcx;
-
-        let substs = tcx.mk_substs_trait(ty, &[]);
-
-        // `func == Clone::clone(&ty) -> ty`
-        let func_ty = tcx.mk_fn_def(self.def_id, substs);
-        let func = Operand::Constant(Box::new(Constant {
-            span: self.span,
-            user_ty: None,
-            literal: ty::Const::zero_sized(tcx, func_ty).into(),
-        }));
-
-        let ref_loc = self.make_place(
-            Mutability::Not,
-            tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty, mutbl: hir::Mutability::Not }),
-        );
-
-        // `let ref_loc: &ty = &src;`
-        let statement = self.make_statement(StatementKind::Assign(Box::new((
-            ref_loc,
-            Rvalue::Ref(tcx.lifetimes.re_erased, BorrowKind::Shared, src),
-        ))));
-
-        // `let loc = Clone::clone(ref_loc);`
-        self.block(
-            vec![statement],
-            TerminatorKind::Call {
-                func,
-                args: vec![Operand::Move(ref_loc)],
-                destination: Some((dest, next)),
-                cleanup: Some(cleanup),
-                from_hir_call: true,
-                fn_span: self.span,
-            },
-            false,
-        );
-    }
-
-    fn loop_header(
-        &mut self,
-        beg: Place<'tcx>,
-        end: Place<'tcx>,
-        loop_body: BasicBlock,
-        loop_end: BasicBlock,
-        is_cleanup: bool,
-    ) {
-        let tcx = self.tcx;
-
-        let cond = self.make_place(Mutability::Mut, tcx.types.bool);
-        let compute_cond = self.make_statement(StatementKind::Assign(Box::new((
-            cond,
-            Rvalue::BinaryOp(BinOp::Ne, Box::new((Operand::Copy(end), Operand::Copy(beg)))),
-        ))));
-
-        // `if end != beg { goto loop_body; } else { goto loop_end; }`
-        self.block(
-            vec![compute_cond],
-            TerminatorKind::if_(tcx, Operand::Move(cond), loop_body, loop_end),
-            is_cleanup,
-        );
-    }
-
-    fn make_usize(&self, value: u64) -> Box<Constant<'tcx>> {
-        Box::new(Constant {
-            span: self.span,
-            user_ty: None,
-            literal: ty::Const::from_usize(self.tcx, value).into(),
-        })
-    }
-
-    fn array_shim(
-        &mut self,
-        dest: Place<'tcx>,
-        src: Place<'tcx>,
-        ty: Ty<'tcx>,
-        len: &'tcx ty::Const<'tcx>,
-    ) {
-        let tcx = self.tcx;
-        let span = self.span;
-
-        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
-        let end = self.make_place(Mutability::Not, tcx.types.usize);
-
-        // BB #0
-        // `let mut beg = 0;`
-        // `let end = len;`
-        // `goto #1;`
-        let inits = vec![
-            self.make_statement(StatementKind::Assign(Box::new((
-                Place::from(beg),
-                Rvalue::Use(Operand::Constant(self.make_usize(0))),
-            )))),
-            self.make_statement(StatementKind::Assign(Box::new((
-                end,
-                Rvalue::Use(Operand::Constant(Box::new(Constant {
-                    span: self.span,
-                    user_ty: None,
-                    literal: len.into(),
-                }))),
-            )))),
-        ];
-        self.block(inits, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
-        // BB #1: loop {
-        //     BB #2;
-        //     BB #3;
-        // }
-        // BB #4;
-        self.loop_header(Place::from(beg), end, BasicBlock::new(2), BasicBlock::new(4), false);
-
-        // BB #2
-        // `dest[i] = Clone::clone(src[beg])`;
-        // Goto #3 if ok, #5 if unwinding happens.
-        let dest_field = self.tcx.mk_place_index(dest, beg);
-        let src_field = self.tcx.mk_place_index(src, beg);
-        self.make_clone_call(dest_field, src_field, ty, BasicBlock::new(3), BasicBlock::new(5));
-
-        // BB #3
-        // `beg = beg + 1;`
-        // `goto #1`;
-        let statements = vec![self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::BinaryOp(
-                BinOp::Add,
-                Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
-            ),
-        ))))];
-        self.block(statements, TerminatorKind::Goto { target: BasicBlock::new(1) }, false);
-
-        // BB #4
-        // `return dest;`
-        self.block(vec![], TerminatorKind::Return, false);
-
-        // BB #5 (cleanup)
-        // `let end = beg;`
-        // `let mut beg = 0;`
-        // goto #6;
-        let end = beg;
-        let beg = self.local_decls.push(LocalDecl::new(tcx.types.usize, span));
-        let init = self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::Use(Operand::Constant(self.make_usize(0))),
-        ))));
-        self.block(vec![init], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
-        // BB #6 (cleanup): loop {
-        //     BB #7;
-        //     BB #8;
-        // }
-        // BB #9;
-        self.loop_header(
-            Place::from(beg),
-            Place::from(end),
-            BasicBlock::new(7),
-            BasicBlock::new(9),
-            true,
-        );
-
-        // BB #7 (cleanup)
-        // `drop(dest[beg])`;
-        self.block(
-            vec![],
-            TerminatorKind::Drop {
-                place: self.tcx.mk_place_index(dest, beg),
-                target: BasicBlock::new(8),
-                unwind: None,
-            },
-            true,
-        );
-
-        // BB #8 (cleanup)
-        // `beg = beg + 1;`
-        // `goto #6;`
-        let statement = self.make_statement(StatementKind::Assign(Box::new((
-            Place::from(beg),
-            Rvalue::BinaryOp(
-                BinOp::Add,
-                Box::new((Operand::Copy(Place::from(beg)), Operand::Constant(self.make_usize(1)))),
-            ),
-        ))));
-        self.block(vec![statement], TerminatorKind::Goto { target: BasicBlock::new(6) }, true);
-
-        // BB #9 (resume)
-        self.block(vec![], TerminatorKind::Resume, true);
-    }
-
-    fn tuple_like_shim<I>(&mut self, dest: Place<'tcx>, src: Place<'tcx>, tys: I)
-    where
-        I: Iterator<Item = Ty<'tcx>>,
-    {
-        let mut previous_field = None;
-        for (i, ity) in tys.enumerate() {
-            let field = Field::new(i);
-            let src_field = self.tcx.mk_place_field(src, field, ity);
-
-            let dest_field = self.tcx.mk_place_field(dest, field, ity);
-
-            // #(2i + 1) is the cleanup block for the previous clone operation
-            let cleanup_block = self.block_index_offset(1);
-            // #(2i + 2) is the next cloning block
-            // (or the Return terminator if this is the last block)
-            let next_block = self.block_index_offset(2);
-
-            // BB #(2i)
-            // `dest.i = Clone::clone(&src.i);`
-            // Goto #(2i + 2) if ok, #(2i + 1) if unwinding happens.
-            self.make_clone_call(dest_field, src_field, ity, next_block, cleanup_block);
-
-            // BB #(2i + 1) (cleanup)
-            if let Some((previous_field, previous_cleanup)) = previous_field.take() {
-                // Drop previous field and goto previous cleanup block.
-                self.block(
-                    vec![],
-                    TerminatorKind::Drop {
-                        place: previous_field,
-                        target: previous_cleanup,
-                        unwind: None,
-                    },
-                    true,
-                );
-            } else {
-                // Nothing to drop, just resume.
-                self.block(vec![], TerminatorKind::Resume, true);
-            }
-
-            previous_field = Some((dest_field, cleanup_block));
-        }
-
-        self.block(vec![], TerminatorKind::Return, false);
-    }
-}
-
-/// Builds a "call" shim for `instance`. The shim calls the function specified by `call_kind`,
-/// first adjusting its first argument according to `rcvr_adjustment`.
-fn build_call_shim<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: ty::InstanceDef<'tcx>,
-    rcvr_adjustment: Option<Adjustment>,
-    call_kind: CallKind<'tcx>,
-) -> Body<'tcx> {
-    debug!(
-        "build_call_shim(instance={:?}, rcvr_adjustment={:?}, call_kind={:?})",
-        instance, rcvr_adjustment, call_kind
-    );
-
-    // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used
-    // to substitute into the signature of the shim. It is not necessary for users of this
-    // MIR body to perform further substitutions (see `InstanceDef::has_polymorphic_mir_body`).
-    let (sig_substs, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance {
-        let sig = tcx.erase_late_bound_regions(ty.fn_sig(tcx));
-
-        let untuple_args = sig.inputs();
-
-        // Create substitutions for the `Self` and `Args` generic parameters of the shim body.
-        let arg_tup = tcx.mk_tup(untuple_args.iter());
-        let sig_substs = tcx.mk_substs_trait(ty, &[ty::subst::GenericArg::from(arg_tup)]);
-
-        (Some(sig_substs), Some(untuple_args))
-    } else {
-        (None, None)
-    };
-
-    let def_id = instance.def_id();
-    let sig = tcx.fn_sig(def_id);
-    let mut sig = tcx.erase_late_bound_regions(sig);
-
-    assert_eq!(sig_substs.is_some(), !instance.has_polymorphic_mir_body());
-    if let Some(sig_substs) = sig_substs {
-        sig = sig.subst(tcx, sig_substs);
-    }
-
-    if let CallKind::Indirect(fnty) = call_kind {
-        // `sig` determines our local decls, and thus the callee type in the `Call` terminator. This
-        // can only be an `FnDef` or `FnPtr`, but currently will be `Self` since the types come from
-        // the implemented `FnX` trait.
-
-        // Apply the opposite adjustment to the MIR input.
-        let mut inputs_and_output = sig.inputs_and_output.to_vec();
-
-        // Initial signature is `fn(&? Self, Args) -> Self::Output` where `Args` is a tuple of the
-        // fn arguments. `Self` may be passed via (im)mutable reference or by-value.
-        assert_eq!(inputs_and_output.len(), 3);
-
-        // `Self` is always the original fn type `ty`. The MIR call terminator is only defined for
-        // `FnDef` and `FnPtr` callees, not the `Self` type param.
-        let self_arg = &mut inputs_and_output[0];
-        *self_arg = match rcvr_adjustment.unwrap() {
-            Adjustment::Identity => fnty,
-            Adjustment::Deref => tcx.mk_imm_ptr(fnty),
-            Adjustment::RefMut => tcx.mk_mut_ptr(fnty),
-        };
-        sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
-    }
-
-    // FIXME(eddyb) avoid having this snippet both here and in
-    // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?).
-    if let ty::InstanceDef::VtableShim(..) = instance {
-        // Modify fn(self, ...) to fn(self: *mut Self, ...)
-        let mut inputs_and_output = sig.inputs_and_output.to_vec();
-        let self_arg = &mut inputs_and_output[0];
-        debug_assert!(tcx.generics_of(def_id).has_self && *self_arg == tcx.types.self_param);
-        *self_arg = tcx.mk_mut_ptr(*self_arg);
-        sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
-    }
-
-    let span = tcx.def_span(def_id);
-
-    debug!("build_call_shim: sig={:?}", sig);
-
-    let mut local_decls = local_decls_for_sig(&sig, span);
-    let source_info = SourceInfo::outermost(span);
-
-    let rcvr_place = || {
-        assert!(rcvr_adjustment.is_some());
-        Place::from(Local::new(1 + 0))
-    };
-    let mut statements = vec![];
-
-    let rcvr = rcvr_adjustment.map(|rcvr_adjustment| match rcvr_adjustment {
-        Adjustment::Identity => Operand::Move(rcvr_place()),
-        Adjustment::Deref => Operand::Move(tcx.mk_place_deref(rcvr_place())),
-        Adjustment::RefMut => {
-            // let rcvr = &mut rcvr;
-            let ref_rcvr = local_decls.push(
-                LocalDecl::new(
-                    tcx.mk_ref(
-                        tcx.lifetimes.re_erased,
-                        ty::TypeAndMut { ty: sig.inputs()[0], mutbl: hir::Mutability::Mut },
-                    ),
-                    span,
-                )
-                .immutable(),
-            );
-            let borrow_kind = BorrowKind::Mut { allow_two_phase_borrow: false };
-            statements.push(Statement {
-                source_info,
-                kind: StatementKind::Assign(Box::new((
-                    Place::from(ref_rcvr),
-                    Rvalue::Ref(tcx.lifetimes.re_erased, borrow_kind, rcvr_place()),
-                ))),
-            });
-            Operand::Move(Place::from(ref_rcvr))
-        }
-    });
-
-    let (callee, mut args) = match call_kind {
-        // `FnPtr` call has no receiver. Args are untupled below.
-        CallKind::Indirect(_) => (rcvr.unwrap(), vec![]),
-
-        // `FnDef` call with optional receiver.
-        CallKind::Direct(def_id) => {
-            let ty = tcx.type_of(def_id);
-            (
-                Operand::Constant(Box::new(Constant {
-                    span,
-                    user_ty: None,
-                    literal: ty::Const::zero_sized(tcx, ty).into(),
-                })),
-                rcvr.into_iter().collect::<Vec<_>>(),
-            )
-        }
-    };
-
-    let mut arg_range = 0..sig.inputs().len();
-
-    // Take the `self` ("receiver") argument out of the range (it's adjusted above).
-    if rcvr_adjustment.is_some() {
-        arg_range.start += 1;
-    }
-
-    // Take the last argument, if we need to untuple it (handled below).
-    if untuple_args.is_some() {
-        arg_range.end -= 1;
-    }
-
-    // Pass all of the non-special arguments directly.
-    args.extend(arg_range.map(|i| Operand::Move(Place::from(Local::new(1 + i)))));
-
-    // Untuple the last argument, if we have to.
-    if let Some(untuple_args) = untuple_args {
-        let tuple_arg = Local::new(1 + (sig.inputs().len() - 1));
-        args.extend(untuple_args.iter().enumerate().map(|(i, ity)| {
-            Operand::Move(tcx.mk_place_field(Place::from(tuple_arg), Field::new(i), *ity))
-        }));
-    }
-
-    let n_blocks = if let Some(Adjustment::RefMut) = rcvr_adjustment { 5 } else { 2 };
-    let mut blocks = IndexVec::with_capacity(n_blocks);
-    let block = |blocks: &mut IndexVec<_, _>, statements, kind, is_cleanup| {
-        blocks.push(BasicBlockData {
-            statements,
-            terminator: Some(Terminator { source_info, kind }),
-            is_cleanup,
-        })
-    };
-
-    // BB #0
-    block(
-        &mut blocks,
-        statements,
-        TerminatorKind::Call {
-            func: callee,
-            args,
-            destination: Some((Place::return_place(), BasicBlock::new(1))),
-            cleanup: if let Some(Adjustment::RefMut) = rcvr_adjustment {
-                Some(BasicBlock::new(3))
-            } else {
-                None
-            },
-            from_hir_call: true,
-            fn_span: span,
-        },
-        false,
-    );
-
-    if let Some(Adjustment::RefMut) = rcvr_adjustment {
-        // BB #1 - drop for Self
-        block(
-            &mut blocks,
-            vec![],
-            TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(2), unwind: None },
-            false,
-        );
-    }
-    // BB #1/#2 - return
-    block(&mut blocks, vec![], TerminatorKind::Return, false);
-    if let Some(Adjustment::RefMut) = rcvr_adjustment {
-        // BB #3 - drop if closure panics
-        block(
-            &mut blocks,
-            vec![],
-            TerminatorKind::Drop { place: rcvr_place(), target: BasicBlock::new(4), unwind: None },
-            true,
-        );
-
-        // BB #4 - resume
-        block(&mut blocks, vec![], TerminatorKind::Resume, true);
-    }
-
-    let mut body = new_body(
-        tcx,
-        MirSource::from_instance(instance),
-        blocks,
-        local_decls,
-        sig.inputs().len(),
-        span,
-    );
-
-    if let Abi::RustCall = sig.abi {
-        body.spread_arg = Some(Local::new(sig.inputs().len()));
-    }
-
-    body
-}
-
-pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
-    debug_assert!(tcx.is_constructor(ctor_id));
-
-    let span =
-        tcx.hir().span_if_local(ctor_id).unwrap_or_else(|| bug!("no span for ctor {:?}", ctor_id));
-
-    let param_env = tcx.param_env(ctor_id);
-
-    // Normalize the sig.
-    let sig = tcx.fn_sig(ctor_id).no_bound_vars().expect("LBR in ADT constructor signature");
-    let sig = tcx.normalize_erasing_regions(param_env, sig);
-
-    let (adt_def, substs) = match sig.output().kind() {
-        ty::Adt(adt_def, substs) => (adt_def, substs),
-        _ => bug!("unexpected type for ADT ctor {:?}", sig.output()),
-    };
-
-    debug!("build_ctor: ctor_id={:?} sig={:?}", ctor_id, sig);
-
-    let local_decls = local_decls_for_sig(&sig, span);
-
-    let source_info = SourceInfo::outermost(span);
-
-    let variant_index = if adt_def.is_enum() {
-        adt_def.variant_index_with_ctor_id(ctor_id)
-    } else {
-        VariantIdx::new(0)
-    };
-
-    // Generate the following MIR:
-    //
-    // (return as Variant).field0 = arg0;
-    // (return as Variant).field1 = arg1;
-    //
-    // return;
-    debug!("build_ctor: variant_index={:?}", variant_index);
-
-    let statements = expand_aggregate(
-        Place::return_place(),
-        adt_def.variants[variant_index].fields.iter().enumerate().map(|(idx, field_def)| {
-            (Operand::Move(Place::from(Local::new(idx + 1))), field_def.ty(tcx, substs))
-        }),
-        AggregateKind::Adt(adt_def, variant_index, substs, None, None),
-        source_info,
-        tcx,
-    )
-    .collect();
-
-    let start_block = BasicBlockData {
-        statements,
-        terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }),
-        is_cleanup: false,
-    };
-
-    let source = MirSource::item(ctor_id);
-    let body = new_body(
-        tcx,
-        source,
-        IndexVec::from_elem_n(start_block, 1),
-        local_decls,
-        sig.inputs().len(),
-        span,
-    );
-
-    crate::util::dump_mir(tcx, None, "mir_map", &0, &body, |_, _| Ok(()));
-
-    body
-}
diff --git a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs b/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
deleted file mode 100644
index aecb2373eaf..00000000000
--- a/compiler/rustc_mir/src/transform/abort_unwinding_calls.rs
+++ /dev/null
@@ -1,141 +0,0 @@
-use crate::transform::MirPass;
-use rustc_hir::def::DefKind;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::*;
-use rustc_middle::ty::layout;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_target::spec::abi::Abi;
-
-/// A pass that runs which is targeted at ensuring that codegen guarantees about
-/// unwinding are upheld for compilations of panic=abort programs.
-///
-/// When compiling with panic=abort codegen backends generally want to assume
-/// that all Rust-defined functions do not unwind, and it's UB if they actually
-/// do unwind. Foreign functions, however, can be declared as "may unwind" via
-/// their ABI (e.g. `extern "C-unwind"`). To uphold the guarantees that
-/// Rust-defined functions never unwind a well-behaved Rust program needs to
-/// catch unwinding from foreign functions and force them to abort.
-///
-/// This pass walks over all functions calls which may possibly unwind,
-/// and if any are found sets their cleanup to a block that aborts the process.
-/// This forces all unwinds, in panic=abort mode happening in foreign code, to
-/// trigger a process abort.
-#[derive(PartialEq)]
-pub struct AbortUnwindingCalls;
-
-impl<'tcx> MirPass<'tcx> for AbortUnwindingCalls {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let def_id = body.source.def_id();
-        let kind = tcx.def_kind(def_id);
-
-        // We don't simplify the MIR of constants at this time because that
-        // namely results in a cyclic query when we call `tcx.type_of` below.
-        let is_function = match kind {
-            DefKind::Fn | DefKind::AssocFn | DefKind::Ctor(..) => true,
-            _ => tcx.is_closure(def_id),
-        };
-        if !is_function {
-            return;
-        }
-
-        // This pass only runs on functions which themselves cannot unwind,
-        // forcibly changing the body of the function to structurally provide
-        // this guarantee by aborting on an unwind. If this function can unwind,
-        // then there's nothing to do because it already should work correctly.
-        //
-        // Here we test for this function itself whether its ABI allows
-        // unwinding or not.
-        let body_flags = tcx.codegen_fn_attrs(def_id).flags;
-        let body_ty = tcx.type_of(def_id);
-        let body_abi = match body_ty.kind() {
-            ty::FnDef(..) => body_ty.fn_sig(tcx).abi(),
-            ty::Closure(..) => Abi::RustCall,
-            ty::Generator(..) => Abi::Rust,
-            _ => span_bug!(body.span, "unexpected body ty: {:?}", body_ty),
-        };
-        let body_can_unwind = layout::fn_can_unwind(tcx, body_flags, body_abi);
-
-        // Look in this function body for any basic blocks which are terminated
-        // with a function call, and whose function we're calling may unwind.
-        // This will filter to functions with `extern "C-unwind"` ABIs, for
-        // example.
-        let mut calls_to_terminate = Vec::new();
-        let mut cleanups_to_remove = Vec::new();
-        for (id, block) in body.basic_blocks().iter_enumerated() {
-            if block.is_cleanup {
-                continue;
-            }
-            let terminator = match &block.terminator {
-                Some(terminator) => terminator,
-                None => continue,
-            };
-            let span = terminator.source_info.span;
-
-            let call_can_unwind = match &terminator.kind {
-                TerminatorKind::Call { func, .. } => {
-                    let ty = func.ty(body, tcx);
-                    let sig = ty.fn_sig(tcx);
-                    let flags = match ty.kind() {
-                        ty::FnPtr(_) => CodegenFnAttrFlags::empty(),
-                        ty::FnDef(def_id, _) => tcx.codegen_fn_attrs(*def_id).flags,
-                        _ => span_bug!(span, "invalid callee of type {:?}", ty),
-                    };
-                    layout::fn_can_unwind(tcx, flags, sig.abi())
-                }
-                TerminatorKind::Drop { .. }
-                | TerminatorKind::DropAndReplace { .. }
-                | TerminatorKind::Assert { .. }
-                | TerminatorKind::FalseUnwind { .. } => {
-                    layout::fn_can_unwind(tcx, CodegenFnAttrFlags::empty(), Abi::Rust)
-                }
-                _ => continue,
-            };
-
-            // If this function call can't unwind, then there's no need for it
-            // to have a landing pad. This means that we can remove any cleanup
-            // registered for it.
-            if !call_can_unwind {
-                cleanups_to_remove.push(id);
-                continue;
-            }
-
-            // Otherwise if this function can unwind, then if the outer function
-            // can also unwind there's nothing to do. If the outer function
-            // can't unwind, however, we need to change the landing pad for this
-            // function call to one that aborts.
-            if !body_can_unwind {
-                calls_to_terminate.push(id);
-            }
-        }
-
-        // For call instructions which need to be terminated, we insert a
-        // singular basic block which simply terminates, and then configure the
-        // `cleanup` attribute for all calls we found to this basic block we
-        // insert which means that any unwinding that happens in the functions
-        // will force an abort of the process.
-        if !calls_to_terminate.is_empty() {
-            let bb = BasicBlockData {
-                statements: Vec::new(),
-                is_cleanup: true,
-                terminator: Some(Terminator {
-                    source_info: SourceInfo::outermost(body.span),
-                    kind: TerminatorKind::Abort,
-                }),
-            };
-            let abort_bb = body.basic_blocks_mut().push(bb);
-
-            for bb in calls_to_terminate {
-                let cleanup = body.basic_blocks_mut()[bb].terminator_mut().unwind_mut().unwrap();
-                *cleanup = Some(abort_bb);
-            }
-        }
-
-        for id in cleanups_to_remove {
-            let cleanup = body.basic_blocks_mut()[id].terminator_mut().unwind_mut().unwrap();
-            *cleanup = None;
-        }
-
-        // We may have invalidated some `cleanup` blocks so clean those up now.
-        super::simplify::remove_dead_blocks(tcx, body);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs
deleted file mode 100644
index 12ee6bb4c67..00000000000
--- a/compiler/rustc_mir/src/transform/add_call_guards.rs
+++ /dev/null
@@ -1,86 +0,0 @@
-use crate::transform::MirPass;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-#[derive(PartialEq)]
-pub enum AddCallGuards {
-    AllCallEdges,
-    CriticalCallEdges,
-}
-pub use self::AddCallGuards::*;
-
-/**
- * Breaks outgoing critical edges for call terminators in the MIR.
- *
- * Critical edges are edges that are neither the only edge leaving a
- * block, nor the only edge entering one.
- *
- * When you want something to happen "along" an edge, you can either
- * do at the end of the predecessor block, or at the start of the
- * successor block. Critical edges have to be broken in order to prevent
- * "edge actions" from affecting other edges. We need this for calls that are
- * codegened to LLVM invoke instructions, because invoke is a block terminator
- * in LLVM so we can't insert any code to handle the call's result into the
- * block that performs the call.
- *
- * This function will break those edges by inserting new blocks along them.
- *
- * NOTE: Simplify CFG will happily undo most of the work this pass does.
- *
- */
-
-impl<'tcx> MirPass<'tcx> for AddCallGuards {
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        self.add_call_guards(body);
-    }
-}
-
-impl AddCallGuards {
-    pub fn add_call_guards(&self, body: &mut Body<'_>) {
-        let mut pred_count: IndexVec<_, _> =
-            body.predecessors().iter().map(|ps| ps.len()).collect();
-        pred_count[START_BLOCK] += 1;
-
-        // We need a place to store the new blocks generated
-        let mut new_blocks = Vec::new();
-
-        let cur_len = body.basic_blocks().len();
-
-        for block in body.basic_blocks_mut() {
-            match block.terminator {
-                Some(Terminator {
-                    kind:
-                        TerminatorKind::Call {
-                            destination: Some((_, ref mut destination)),
-                            cleanup,
-                            ..
-                        },
-                    source_info,
-                }) if pred_count[*destination] > 1
-                    && (cleanup.is_some() || self == &AllCallEdges) =>
-                {
-                    // It's a critical edge, break it
-                    let call_guard = BasicBlockData {
-                        statements: vec![],
-                        is_cleanup: block.is_cleanup,
-                        terminator: Some(Terminator {
-                            source_info,
-                            kind: TerminatorKind::Goto { target: *destination },
-                        }),
-                    };
-
-                    // Get the index it will be when inserted into the MIR
-                    let idx = cur_len + new_blocks.len();
-                    new_blocks.push(call_guard);
-                    *destination = BasicBlock::new(idx);
-                }
-                _ => {}
-            }
-        }
-
-        debug!("Broke {} N edges", new_blocks.len());
-
-        body.basic_blocks_mut().extend(new_blocks);
-    }
-}
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
deleted file mode 100644
index 417e0a51aec..00000000000
--- a/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs
+++ /dev/null
@@ -1,108 +0,0 @@
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-use crate::transform::MirPass;
-use crate::util;
-use crate::util::patch::MirPatch;
-
-// This pass moves values being dropped that are within a packed
-// struct to a separate local before dropping them, to ensure that
-// they are dropped from an aligned address.
-//
-// For example, if we have something like
-// ```Rust
-//     #[repr(packed)]
-//     struct Foo {
-//         dealign: u8,
-//         data: Vec<u8>
-//     }
-//
-//     let foo = ...;
-// ```
-//
-// We want to call `drop_in_place::<Vec<u8>>` on `data` from an aligned
-// address. This means we can't simply drop `foo.data` directly, because
-// its address is not aligned.
-//
-// Instead, we move `foo.data` to a local and drop that:
-// ```
-//     storage.live(drop_temp)
-//     drop_temp = foo.data;
-//     drop(drop_temp) -> next
-// next:
-//     storage.dead(drop_temp)
-// ```
-//
-// The storage instructions are required to avoid stack space
-// blowup.
-
-pub struct AddMovesForPackedDrops;
-
-impl<'tcx> MirPass<'tcx> for AddMovesForPackedDrops {
-    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);
-    }
-}
-
-pub fn add_moves_for_packed_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let patch = add_moves_for_packed_drops_patch(tcx, body);
-    patch.apply(body);
-}
-
-fn add_moves_for_packed_drops_patch<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> MirPatch<'tcx> {
-    let def_id = body.source.def_id();
-    let mut patch = MirPatch::new(body);
-    let param_env = tcx.param_env(def_id);
-
-    for (bb, data) in body.basic_blocks().iter_enumerated() {
-        let loc = Location { block: bb, statement_index: data.statements.len() };
-        let terminator = data.terminator();
-
-        match terminator.kind {
-            TerminatorKind::Drop { place, .. }
-                if util::is_disaligned(tcx, body, param_env, place) =>
-            {
-                add_move_for_packed_drop(tcx, body, &mut patch, terminator, loc, data.is_cleanup);
-            }
-            TerminatorKind::DropAndReplace { .. } => {
-                span_bug!(terminator.source_info.span, "replace in AddMovesForPackedDrops");
-            }
-            _ => {}
-        }
-    }
-
-    patch
-}
-
-fn add_move_for_packed_drop<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    patch: &mut MirPatch<'tcx>,
-    terminator: &Terminator<'tcx>,
-    loc: Location,
-    is_cleanup: bool,
-) {
-    debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
-    let (place, target, unwind) = match terminator.kind {
-        TerminatorKind::Drop { ref place, target, unwind } => (place, target, unwind),
-        _ => unreachable!(),
-    };
-
-    let source_info = terminator.source_info;
-    let ty = place.ty(body, tcx).ty;
-    let temp = patch.new_temp(ty, terminator.source_info.span);
-
-    let storage_dead_block = patch.new_block(BasicBlockData {
-        statements: vec![Statement { source_info, kind: StatementKind::StorageDead(temp) }],
-        terminator: Some(Terminator { source_info, kind: TerminatorKind::Goto { target } }),
-        is_cleanup,
-    });
-
-    patch.add_statement(loc, StatementKind::StorageLive(temp));
-    patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
-    patch.patch_terminator(
-        loc.block,
-        TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
-    );
-}
diff --git a/compiler/rustc_mir/src/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs
deleted file mode 100644
index cb608819ea8..00000000000
--- a/compiler/rustc_mir/src/transform/add_retag.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-//! This pass adds validation calls (AcquireValid, ReleaseValid) where appropriate.
-//! It has to be run really early, before transformations like inlining, because
-//! introducing these calls *adds* UB -- so, conceptually, this pass is actually part
-//! of MIR building, and only after this pass we think of the program has having the
-//! normal MIR semantics.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct AddRetag;
-
-/// Determines whether this place is "stable": Whether, if we evaluate it again
-/// after the assignment, we can be sure to obtain the same place value.
-/// (Concurrent accesses by other threads are no problem as these are anyway non-atomic
-/// copies.  Data races are UB.)
-fn is_stable(place: PlaceRef<'_>) -> bool {
-    place.projection.iter().all(|elem| {
-        match elem {
-            // Which place this evaluates to can change with any memory write,
-            // so cannot assume this to be stable.
-            ProjectionElem::Deref => false,
-            // Array indices are interesting, but MIR building generates a *fresh*
-            // temporary for every array access, so the index cannot be changed as
-            // a side-effect.
-            ProjectionElem::Index { .. } |
-            // The rest is completely boring, they just offset by a constant.
-            ProjectionElem::Field { .. } |
-            ProjectionElem::ConstantIndex { .. } |
-            ProjectionElem::Subslice { .. } |
-            ProjectionElem::Downcast { .. } => true,
-        }
-    })
-}
-
-/// Determine whether this type may be a reference (or box), and thus needs retagging.
-fn may_be_reference(ty: Ty<'tcx>) -> bool {
-    match ty.kind() {
-        // Primitive types that are not references
-        ty::Bool
-        | ty::Char
-        | ty::Float(_)
-        | ty::Int(_)
-        | ty::Uint(_)
-        | ty::RawPtr(..)
-        | ty::FnPtr(..)
-        | ty::Str
-        | ty::FnDef(..)
-        | ty::Never => false,
-        // References
-        ty::Ref(..) => true,
-        ty::Adt(..) if ty.is_box() => true,
-        // Compound types are not references
-        ty::Array(..) | ty::Slice(..) | ty::Tuple(..) | ty::Adt(..) => false,
-        // Conservative fallback
-        _ => true,
-    }
-}
-
-impl<'tcx> MirPass<'tcx> for AddRetag {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !tcx.sess.opts.debugging_opts.mir_emit_retag {
-            return;
-        }
-
-        // We need an `AllCallEdges` pass before we can do any work.
-        super::add_call_guards::AllCallEdges.run_pass(tcx, body);
-
-        let (span, arg_count) = (body.span, body.arg_count);
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let needs_retag = |place: &Place<'tcx>| {
-            // FIXME: Instead of giving up for unstable places, we should introduce
-            // a temporary and retag on that.
-            is_stable(place.as_ref()) && may_be_reference(place.ty(&*local_decls, tcx).ty)
-        };
-        let place_base_raw = |place: &Place<'tcx>| {
-            // If this is a `Deref`, get the type of what we are deref'ing.
-            let deref_base =
-                place.projection.iter().rposition(|p| matches!(p, ProjectionElem::Deref));
-            if let Some(deref_base) = deref_base {
-                let base_proj = &place.projection[..deref_base];
-                let ty = Place::ty_from(place.local, base_proj, &*local_decls, tcx).ty;
-                ty.is_unsafe_ptr()
-            } else {
-                // Not a deref, and thus not raw.
-                false
-            }
-        };
-
-        // PART 1
-        // Retag arguments at the beginning of the start block.
-        {
-            // FIXME: Consider using just the span covering the function
-            // argument declaration.
-            let source_info = SourceInfo::outermost(span);
-            // Gather all arguments, skip return value.
-            let places = local_decls
-                .iter_enumerated()
-                .skip(1)
-                .take(arg_count)
-                .map(|(local, _)| Place::from(local))
-                .filter(needs_retag);
-            // Emit their retags.
-            basic_blocks[START_BLOCK].statements.splice(
-                0..0,
-                places.map(|place| Statement {
-                    source_info,
-                    kind: StatementKind::Retag(RetagKind::FnEntry, Box::new(place)),
-                }),
-            );
-        }
-
-        // PART 2
-        // Retag return values of functions.  Also escape-to-raw the argument of `drop`.
-        // We collect the return destinations because we cannot mutate while iterating.
-        let returns = basic_blocks
-            .iter_mut()
-            .filter_map(|block_data| {
-                match block_data.terminator().kind {
-                    TerminatorKind::Call { destination: Some(ref destination), .. }
-                        if needs_retag(&destination.0) =>
-                    {
-                        // Remember the return destination for later
-                        Some((block_data.terminator().source_info, destination.0, destination.1))
-                    }
-
-                    // `Drop` is also a call, but it doesn't return anything so we are good.
-                    TerminatorKind::Drop { .. } | TerminatorKind::DropAndReplace { .. } => None,
-                    // Not a block ending in a Call -> ignore.
-                    _ => None,
-                }
-            })
-            .collect::<Vec<_>>();
-        // Now we go over the returns we collected to retag the return values.
-        for (source_info, dest_place, dest_block) in returns {
-            basic_blocks[dest_block].statements.insert(
-                0,
-                Statement {
-                    source_info,
-                    kind: StatementKind::Retag(RetagKind::Default, Box::new(dest_place)),
-                },
-            );
-        }
-
-        // PART 3
-        // Add retag after assignment.
-        for block_data in basic_blocks {
-            // We want to insert statements as we iterate.  To this end, we
-            // iterate backwards using indices.
-            for i in (0..block_data.statements.len()).rev() {
-                let (retag_kind, place) = match block_data.statements[i].kind {
-                    // Retag-as-raw after escaping to a raw pointer, if the referent
-                    // is not already a raw pointer.
-                    StatementKind::Assign(box (lplace, Rvalue::AddressOf(_, ref rplace)))
-                        if !place_base_raw(rplace) =>
-                    {
-                        (RetagKind::Raw, lplace)
-                    }
-                    // Retag after assignments of reference type.
-                    StatementKind::Assign(box (ref place, ref rvalue)) if needs_retag(place) => {
-                        let kind = match rvalue {
-                            Rvalue::Ref(_, borrow_kind, _)
-                                if borrow_kind.allows_two_phase_borrow() =>
-                            {
-                                RetagKind::TwoPhase
-                            }
-                            _ => RetagKind::Default,
-                        };
-                        (kind, *place)
-                    }
-                    // Do nothing for the rest
-                    _ => continue,
-                };
-                // Insert a retag after the statement.
-                let source_info = block_data.statements[i].source_info;
-                block_data.statements.insert(
-                    i + 1,
-                    Statement {
-                        source_info,
-                        kind: StatementKind::Retag(retag_kind, Box::new(place)),
-                    },
-                );
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
deleted file mode 100644
index e2d50ba034a..00000000000
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ /dev/null
@@ -1,157 +0,0 @@
-use rustc_errors::DiagnosticBuilder;
-use rustc_middle::lint::LintDiagnosticBuilder;
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
-use rustc_span::def_id::DefId;
-
-use crate::transform::MirPass;
-
-pub struct CheckConstItemMutation;
-
-impl<'tcx> MirPass<'tcx> for CheckConstItemMutation {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let mut checker = ConstMutationChecker { body, tcx, target_local: None };
-        checker.visit_body(&body);
-    }
-}
-
-struct ConstMutationChecker<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    target_local: Option<Local>,
-}
-
-impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
-    fn is_const_item(&self, local: Local) -> Option<DefId> {
-        if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info {
-            Some(def_id)
-        } else {
-            None
-        }
-    }
-
-    fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
-        let def_id = self.is_const_item(local)?;
-
-        // We avoid linting mutation of a const item if the const's type has a
-        // Drop impl. The Drop logic observes the mutation which was performed.
-        //
-        //     pub struct Log { msg: &'static str }
-        //     pub const LOG: Log = Log { msg: "" };
-        //     impl Drop for Log {
-        //         fn drop(&mut self) { println!("{}", self.msg); }
-        //     }
-        //
-        //     LOG.msg = "wow";  // prints "wow"
-        //
-        // FIXME(https://github.com/rust-lang/rust/issues/77425):
-        // Drop this exception once there is a stable attribute to suppress the
-        // const item mutation lint for a single specific const only. Something
-        // equivalent to:
-        //
-        //     #[const_mutation_allowed]
-        //     pub const LOG: Log = Log { msg: "" };
-        match self.tcx.calculate_dtor(def_id, |_, _| Ok(())) {
-            Some(_) => None,
-            None => Some(def_id),
-        }
-    }
-
-    fn lint_const_item_usage(
-        &self,
-        place: &Place<'tcx>,
-        const_item: DefId,
-        location: Location,
-        decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>,
-    ) {
-        // Don't lint on borrowing/assigning when a dereference is involved.
-        // If we 'leave' the temporary via a dereference, we must
-        // be modifying something else
-        //
-        // `unsafe { *FOO = 0; *BAR.field = 1; }`
-        // `unsafe { &mut *FOO }`
-        // `unsafe { (*ARRAY)[0] = val; }
-        if !place.projection.iter().any(|p| matches!(p, PlaceElem::Deref)) {
-            let source_info = self.body.source_info(location);
-            let lint_root = self.body.source_scopes[source_info.scope]
-                .local_data
-                .as_ref()
-                .assert_crate_local()
-                .lint_root;
-
-            self.tcx.struct_span_lint_hir(
-                CONST_ITEM_MUTATION,
-                lint_root,
-                source_info.span,
-                |lint| {
-                    decorate(lint)
-                        .span_note(self.tcx.def_span(const_item), "`const` item defined here")
-                        .emit()
-                },
-            );
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
-    fn visit_statement(&mut self, stmt: &Statement<'tcx>, loc: Location) {
-        if let StatementKind::Assign(box (lhs, _)) = &stmt.kind {
-            // Check for assignment to fields of a constant
-            // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
-            // so emitting a lint would be redundant.
-            if !lhs.projection.is_empty() {
-                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
-                    self.lint_const_item_usage(&lhs, def_id, loc, |lint| {
-                        let mut lint = lint.build("attempting to modify a `const` item");
-                        lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified");
-                        lint
-                    })
-                }
-            }
-            // We are looking for MIR of the form:
-            //
-            // ```
-            // _1 = const FOO;
-            // _2 = &mut _1;
-            // method_call(_2, ..)
-            // ```
-            //
-            // Record our current LHS, so that we can detect this
-            // pattern in `visit_rvalue`
-            self.target_local = lhs.as_local();
-        }
-        self.super_statement(stmt, loc);
-        self.target_local = None;
-    }
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, loc: Location) {
-        if let Rvalue::Ref(_, BorrowKind::Mut { .. }, place) = rvalue {
-            let local = place.local;
-            if let Some(def_id) = self.is_const_item(local) {
-                // If this Rvalue is being used as the right-hand side of a
-                // `StatementKind::Assign`, see if it ends up getting used as
-                // the `self` parameter of a method call (as the terminator of our current
-                // BasicBlock). If so, we emit a more specific lint.
-                let method_did = self.target_local.and_then(|target_local| {
-                    crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block)
-                });
-                let lint_loc =
-                    if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
-                self.lint_const_item_usage(place, def_id, lint_loc, |lint| {
-                    let mut lint = lint.build("taking a mutable reference to a `const` item");
-                    lint
-                        .note("each usage of a `const` item creates a new temporary")
-                        .note("the mutable reference will refer to this temporary, not the original `const` item");
-
-                    if let Some((method_did, _substs)) = method_did {
-                        lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
-                    }
-
-                    lint
-                });
-            }
-        }
-        self.super_rvalue(rvalue, loc);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs
deleted file mode 100644
index 13b7221046b..00000000000
--- a/compiler/rustc_mir/src/transform/check_packed_ref.rs
+++ /dev/null
@@ -1,115 +0,0 @@
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::mir::visit::{PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::UNALIGNED_REFERENCES;
-use rustc_span::symbol::sym;
-
-use crate::transform::MirPass;
-use crate::util;
-
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers { unsafe_derive_on_repr_packed, ..*providers };
-}
-
-pub struct CheckPackedRef;
-
-impl<'tcx> MirPass<'tcx> for CheckPackedRef {
-    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);
-        let mut checker = PackedRefChecker { body, tcx, param_env, source_info };
-        checker.visit_body(&body);
-    }
-}
-
-struct PackedRefChecker<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    source_info: SourceInfo,
-}
-
-fn unsafe_derive_on_repr_packed(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    let lint_hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-    tcx.struct_span_lint_hir(UNALIGNED_REFERENCES, lint_hir_id, tcx.def_span(def_id), |lint| {
-        // FIXME: when we make this a hard error, this should have its
-        // own error code.
-        let message = if tcx.generics_of(def_id).own_requires_monomorphization() {
-            "`#[derive]` can't be used on a `#[repr(packed)]` struct with \
-             type or const parameters (error E0133)"
-                .to_string()
-        } else {
-            "`#[derive]` can't be used on a `#[repr(packed)]` struct that \
-             does not derive Copy (error E0133)"
-                .to_string()
-        };
-        lint.build(&message).emit()
-    });
-}
-
-fn builtin_derive_def_id(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
-    debug!("builtin_derive_def_id({:?})", def_id);
-    if let Some(impl_def_id) = tcx.impl_of_method(def_id) {
-        if tcx.has_attr(impl_def_id, sym::automatically_derived) {
-            debug!("builtin_derive_def_id({:?}) - is {:?}", def_id, impl_def_id);
-            Some(impl_def_id)
-        } else {
-            debug!("builtin_derive_def_id({:?}) - not automatically derived", def_id);
-            None
-        }
-    } else {
-        debug!("builtin_derive_def_id({:?}) - not a method", def_id);
-        None
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for PackedRefChecker<'a, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        // Make sure we know where in the MIR we are.
-        self.source_info = terminator.source_info;
-        self.super_terminator(terminator, location);
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        // Make sure we know where in the MIR we are.
-        self.source_info = statement.source_info;
-        self.super_statement(statement, location);
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        if context.is_borrow() {
-            if util::is_disaligned(self.tcx, self.body, self.param_env, *place) {
-                let def_id = self.body.source.instance.def_id();
-                if let Some(impl_def_id) = builtin_derive_def_id(self.tcx, def_id) {
-                    // If a method is defined in the local crate,
-                    // the impl containing that method should also be.
-                    self.tcx.ensure().unsafe_derive_on_repr_packed(impl_def_id.expect_local());
-                } else {
-                    let source_info = self.source_info;
-                    let lint_root = self.body.source_scopes[source_info.scope]
-                        .local_data
-                        .as_ref()
-                        .assert_crate_local()
-                        .lint_root;
-                    self.tcx.struct_span_lint_hir(
-                        UNALIGNED_REFERENCES,
-                        lint_root,
-                        source_info.span,
-                        |lint| {
-                            lint.build("reference to packed field is unaligned")
-                                .note(
-                                    "fields of packed structs are not properly aligned, and creating \
-                                    a misaligned reference is undefined behavior (even if that \
-                                    reference is never dereferenced)",
-                                )
-                                .emit()
-                        },
-                    );
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs
deleted file mode 100644
index 1ff9bd15721..00000000000
--- a/compiler/rustc_mir/src/transform/check_unsafety.rs
+++ /dev/null
@@ -1,574 +0,0 @@
-use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::struct_span_err;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::hir_id::HirId;
-use rustc_hir::intravisit;
-use rustc_hir::Node;
-use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
-use rustc_session::lint::Level;
-
-use std::ops::Bound;
-
-pub struct UnsafetyChecker<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    body_did: LocalDefId,
-    violations: Vec<UnsafetyViolation>,
-    source_info: SourceInfo,
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    /// Mark an `unsafe` block as used, so we don't lint it.
-    used_unsafe: FxHashSet<hir::HirId>,
-    inherited_blocks: Vec<(hir::HirId, bool)>,
-}
-
-impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn new(
-        body: &'a Body<'tcx>,
-        body_did: LocalDefId,
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-    ) -> Self {
-        Self {
-            body,
-            body_did,
-            violations: vec![],
-            source_info: SourceInfo::outermost(body.span),
-            tcx,
-            param_env,
-            used_unsafe: Default::default(),
-            inherited_blocks: vec![],
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.source_info = terminator.source_info;
-        match terminator.kind {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                // safe (at least as emitted during MIR construction)
-            }
-
-            TerminatorKind::Call { ref func, .. } => {
-                let func_ty = func.ty(self.body, self.tcx);
-                let sig = func_ty.fn_sig(self.tcx);
-                if let hir::Unsafety::Unsafe = sig.unsafety() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::CallToUnsafeFunction,
-                    )
-                }
-
-                if let ty::FnDef(func_id, _) = func_ty.kind() {
-                    self.check_target_features(*func_id);
-                }
-            }
-
-            TerminatorKind::InlineAsm { .. } => self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::UseOfInlineAssembly,
-            ),
-        }
-        self.super_terminator(terminator, location);
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        self.source_info = statement.source_info;
-        match statement.kind {
-            StatementKind::Assign(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::SetDiscriminant { .. }
-            | StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
-            | StatementKind::Retag { .. }
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::Nop => {
-                // safe (at least as emitted during MIR construction)
-            }
-
-            StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::UseOfInlineAssembly,
-            ),
-            StatementKind::CopyNonOverlapping(..) => unreachable!(),
-        }
-        self.super_statement(statement, location);
-    }
-
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        match rvalue {
-            Rvalue::Aggregate(box ref aggregate, _) => match aggregate {
-                &AggregateKind::Array(..) | &AggregateKind::Tuple => {}
-                &AggregateKind::Adt(ref def, ..) => {
-                    match self.tcx.layout_scalar_valid_range(def.did) {
-                        (Bound::Unbounded, Bound::Unbounded) => {}
-                        _ => self.require_unsafe(
-                            UnsafetyViolationKind::General,
-                            UnsafetyViolationDetails::InitializingTypeWith,
-                        ),
-                    }
-                }
-                &AggregateKind::Closure(def_id, _) | &AggregateKind::Generator(def_id, _, _) => {
-                    let UnsafetyCheckResult { violations, unsafe_blocks } =
-                        self.tcx.unsafety_check_result(def_id.expect_local());
-                    self.register_violations(&violations, &unsafe_blocks);
-                }
-            },
-            _ => {}
-        }
-        self.super_rvalue(rvalue, location);
-    }
-
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
-        // On types with `scalar_valid_range`, prevent
-        // * `&mut x.field`
-        // * `x.field = y;`
-        // * `&x.field` if `field`'s type has interior mutability
-        // because either of these would allow modifying the layout constrained field and
-        // insert values that violate the layout constraints.
-        if context.is_mutating_use() || context.is_borrow() {
-            self.check_mut_borrowing_layout_constrained_field(*place, context.is_mutating_use());
-        }
-
-        // Some checks below need the extra metainfo of the local declaration.
-        let decl = &self.body.local_decls[place.local];
-
-        // Check the base local: it might be an unsafe-to-access static. We only check derefs of the
-        // temporary holding the static pointer to avoid duplicate errors
-        // <https://github.com/rust-lang/rust/pull/78068#issuecomment-731753506>.
-        if decl.internal && place.projection.first() == Some(&ProjectionElem::Deref) {
-            // If the projection root is an artifical local that we introduced when
-            // desugaring `static`, give a more specific error message
-            // (avoid the general "raw pointer" clause below, that would only be confusing).
-            if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info {
-                if self.tcx.is_mutable_static(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfMutableStatic,
-                    );
-                    return;
-                } else if self.tcx.is_foreign_item(def_id) {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::UseOfExternStatic,
-                    );
-                    return;
-                }
-            }
-        }
-
-        // Check for raw pointer `Deref`.
-        for (base, proj) in place.iter_projections() {
-            if proj == ProjectionElem::Deref {
-                let base_ty = base.ty(self.body, self.tcx).ty;
-                if base_ty.is_unsafe_ptr() {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::DerefOfRawPointer,
-                    )
-                }
-            }
-        }
-
-        // Check for union fields. For this we traverse right-to-left, as the last `Deref` changes
-        // whether we *read* the union field or potentially *write* to it (if this place is being assigned to).
-        let mut saw_deref = false;
-        for (base, proj) in place.iter_projections().rev() {
-            if proj == ProjectionElem::Deref {
-                saw_deref = true;
-                continue;
-            }
-
-            let base_ty = base.ty(self.body, self.tcx).ty;
-            if base_ty.is_union() {
-                // If we did not hit a `Deref` yet and the overall place use is an assignment, the
-                // rules are different.
-                let assign_to_field = !saw_deref
-                    && matches!(
-                        context,
-                        PlaceContext::MutatingUse(
-                            MutatingUseContext::Store
-                                | MutatingUseContext::Drop
-                                | MutatingUseContext::AsmOutput
-                        )
-                    );
-                // If this is just an assignment, determine if the assigned type needs dropping.
-                if assign_to_field {
-                    // We have to check the actual type of the assignment, as that determines if the
-                    // old value is being dropped.
-                    let assigned_ty = place.ty(&self.body.local_decls, self.tcx).ty;
-                    // To avoid semver hazard, we only consider `Copy` and `ManuallyDrop` non-dropping.
-                    let manually_drop = assigned_ty
-                        .ty_adt_def()
-                        .map_or(false, |adt_def| adt_def.is_manually_drop());
-                    let nodrop = manually_drop
-                        || assigned_ty.is_copy_modulo_regions(
-                            self.tcx.at(self.source_info.span),
-                            self.param_env,
-                        );
-                    if !nodrop {
-                        self.require_unsafe(
-                            UnsafetyViolationKind::General,
-                            UnsafetyViolationDetails::AssignToDroppingUnionField,
-                        );
-                    } else {
-                        // write to non-drop union field, safe
-                    }
-                } else {
-                    self.require_unsafe(
-                        UnsafetyViolationKind::General,
-                        UnsafetyViolationDetails::AccessToUnionField,
-                    )
-                }
-            }
-        }
-    }
-}
-
-impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> {
-    fn require_unsafe(&mut self, kind: UnsafetyViolationKind, details: UnsafetyViolationDetails) {
-        // Violations can turn out to be `UnsafeFn` during analysis, but they should not start out as such.
-        assert_ne!(kind, UnsafetyViolationKind::UnsafeFn);
-
-        let source_info = self.source_info;
-        let lint_root = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .lint_root;
-        self.register_violations(
-            &[UnsafetyViolation { source_info, lint_root, kind, details }],
-            &[],
-        );
-    }
-
-    fn register_violations(
-        &mut self,
-        violations: &[UnsafetyViolation],
-        unsafe_blocks: &[(hir::HirId, bool)],
-    ) {
-        let safety = self.body.source_scopes[self.source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .safety;
-        let within_unsafe = match safety {
-            // `unsafe` blocks are required in safe code
-            Safety::Safe => {
-                for violation in violations {
-                    match violation.kind {
-                        UnsafetyViolationKind::General => {}
-                        UnsafetyViolationKind::UnsafeFn => {
-                            bug!("`UnsafetyViolationKind::UnsafeFn` in an `Safe` context")
-                        }
-                    }
-                    if !self.violations.contains(violation) {
-                        self.violations.push(*violation)
-                    }
-                }
-                false
-            }
-            // With the RFC 2585, no longer allow `unsafe` operations in `unsafe fn`s
-            Safety::FnUnsafe => {
-                for violation in violations {
-                    let mut violation = *violation;
-
-                    violation.kind = UnsafetyViolationKind::UnsafeFn;
-                    if !self.violations.contains(&violation) {
-                        self.violations.push(violation)
-                    }
-                }
-                false
-            }
-            Safety::BuiltinUnsafe => true,
-            Safety::ExplicitUnsafe(hir_id) => {
-                // mark unsafe block as used if there are any unsafe operations inside
-                if !violations.is_empty() {
-                    self.used_unsafe.insert(hir_id);
-                }
-                true
-            }
-        };
-        self.inherited_blocks.extend(
-            unsafe_blocks.iter().map(|&(hir_id, is_used)| (hir_id, is_used && !within_unsafe)),
-        );
-    }
-    fn check_mut_borrowing_layout_constrained_field(
-        &mut self,
-        place: Place<'tcx>,
-        is_mut_use: bool,
-    ) {
-        for (place_base, elem) in place.iter_projections().rev() {
-            match elem {
-                // Modifications behind a dereference don't affect the value of
-                // the pointer.
-                ProjectionElem::Deref => return,
-                ProjectionElem::Field(..) => {
-                    let ty = place_base.ty(&self.body.local_decls, self.tcx).ty;
-                    if let ty::Adt(def, _) = ty.kind() {
-                        if self.tcx.layout_scalar_valid_range(def.did)
-                            != (Bound::Unbounded, Bound::Unbounded)
-                        {
-                            let details = if is_mut_use {
-                                UnsafetyViolationDetails::MutationOfLayoutConstrainedField
-
-                            // Check `is_freeze` as late as possible to avoid cycle errors
-                            // with opaque types.
-                            } else if !place
-                                .ty(self.body, self.tcx)
-                                .ty
-                                .is_freeze(self.tcx.at(self.source_info.span), self.param_env)
-                            {
-                                UnsafetyViolationDetails::BorrowOfLayoutConstrainedField
-                            } else {
-                                continue;
-                            };
-                            self.require_unsafe(UnsafetyViolationKind::General, details);
-                        }
-                    }
-                }
-                _ => {}
-            }
-        }
-    }
-
-    /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether
-    /// the called function has target features the calling function hasn't.
-    fn check_target_features(&mut self, func_did: DefId) {
-        // Unsafety isn't required on wasm targets. For more information see
-        // the corresponding check in typeck/src/collect.rs
-        if self.tcx.sess.target.options.is_like_wasm {
-            return;
-        }
-
-        let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features;
-        let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features;
-
-        // Is `callee_features` a subset of `calling_features`?
-        if !callee_features.iter().all(|feature| self_features.contains(feature)) {
-            self.require_unsafe(
-                UnsafetyViolationKind::General,
-                UnsafetyViolationDetails::CallToFunctionWith,
-            )
-        }
-    }
-}
-
-pub(crate) fn provide(providers: &mut Providers) {
-    *providers = Providers {
-        unsafety_check_result: |tcx, def_id| {
-            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.unsafety_check_result_for_const_arg(def)
-            } else {
-                unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
-            }
-        },
-        unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
-            unsafety_check_result(
-                tcx,
-                ty::WithOptConstParam { did, const_param_did: Some(param_did) },
-            )
-        },
-        ..*providers
-    };
-}
-
-struct UnusedUnsafeVisitor<'a> {
-    used_unsafe: &'a FxHashSet<hir::HirId>,
-    unsafe_blocks: &'a mut Vec<(hir::HirId, bool)>,
-}
-
-impl<'a, 'tcx> intravisit::Visitor<'tcx> for UnusedUnsafeVisitor<'a> {
-    type Map = intravisit::ErasedMap<'tcx>;
-
-    fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> {
-        intravisit::NestedVisitorMap::None
-    }
-
-    fn visit_block(&mut self, block: &'tcx hir::Block<'tcx>) {
-        intravisit::walk_block(self, block);
-
-        if let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules {
-            self.unsafe_blocks.push((block.hir_id, self.used_unsafe.contains(&block.hir_id)));
-        }
-    }
-}
-
-fn check_unused_unsafe(
-    tcx: TyCtxt<'_>,
-    def_id: LocalDefId,
-    used_unsafe: &FxHashSet<hir::HirId>,
-    unsafe_blocks: &mut Vec<(hir::HirId, bool)>,
-) {
-    let body_id = tcx.hir().maybe_body_owned_by(tcx.hir().local_def_id_to_hir_id(def_id));
-
-    let body_id = match body_id {
-        Some(body) => body,
-        None => {
-            debug!("check_unused_unsafe({:?}) - no body found", def_id);
-            return;
-        }
-    };
-    let body = tcx.hir().body(body_id);
-    debug!("check_unused_unsafe({:?}, body={:?}, used_unsafe={:?})", def_id, body, used_unsafe);
-
-    let mut visitor = UnusedUnsafeVisitor { used_unsafe, unsafe_blocks };
-    intravisit::Visitor::visit_body(&mut visitor, body);
-}
-
-fn unsafety_check_result<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx UnsafetyCheckResult {
-    debug!("unsafety_violations({:?})", def);
-
-    // N.B., this borrow is valid because all the consumers of
-    // `mir_built` force this.
-    let body = &tcx.mir_built(def).borrow();
-
-    let param_env = tcx.param_env(def.did);
-
-    let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
-    checker.visit_body(&body);
-
-    check_unused_unsafe(tcx, def.did, &checker.used_unsafe, &mut checker.inherited_blocks);
-
-    tcx.arena.alloc(UnsafetyCheckResult {
-        violations: checker.violations.into(),
-        unsafe_blocks: checker.inherited_blocks.into(),
-    })
-}
-
-/// Returns the `HirId` for an enclosing scope that is also `unsafe`.
-fn is_enclosed(
-    tcx: TyCtxt<'_>,
-    used_unsafe: &FxHashSet<hir::HirId>,
-    id: hir::HirId,
-    unsafe_op_in_unsafe_fn_allowed: bool,
-) -> Option<(&'static str, hir::HirId)> {
-    let parent_id = tcx.hir().get_parent_node(id);
-    if parent_id != id {
-        if used_unsafe.contains(&parent_id) {
-            Some(("block", parent_id))
-        } else if let Some(Node::Item(&hir::Item {
-            kind: hir::ItemKind::Fn(ref sig, _, _), ..
-        })) = tcx.hir().find(parent_id)
-        {
-            if sig.header.unsafety == hir::Unsafety::Unsafe && unsafe_op_in_unsafe_fn_allowed {
-                Some(("fn", parent_id))
-            } else {
-                None
-            }
-        } else {
-            is_enclosed(tcx, used_unsafe, parent_id, unsafe_op_in_unsafe_fn_allowed)
-        }
-    } else {
-        None
-    }
-}
-
-fn report_unused_unsafe(tcx: TyCtxt<'_>, used_unsafe: &FxHashSet<hir::HirId>, id: hir::HirId) {
-    let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
-    tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, |lint| {
-        let msg = "unnecessary `unsafe` block";
-        let mut db = lint.build(msg);
-        db.span_label(span, msg);
-        if let Some((kind, id)) =
-            is_enclosed(tcx, used_unsafe, id, unsafe_op_in_unsafe_fn_allowed(tcx, id))
-        {
-            db.span_label(
-                tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
-                format!("because it's nested under this `unsafe` {}", kind),
-            );
-        }
-        db.emit();
-    });
-}
-
-pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
-    debug!("check_unsafety({:?})", def_id);
-
-    // closures are handled by their parent fn.
-    if tcx.is_closure(def_id.to_def_id()) {
-        return;
-    }
-
-    let UnsafetyCheckResult { violations, unsafe_blocks } = tcx.unsafety_check_result(def_id);
-
-    for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
-        let (description, note) = details.description_and_note();
-
-        // Report an error.
-        let unsafe_fn_msg =
-            if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) { " function or" } else { "" };
-
-        match kind {
-            UnsafetyViolationKind::General => {
-                // once
-                struct_span_err!(
-                    tcx.sess,
-                    source_info.span,
-                    E0133,
-                    "{} is unsafe and requires unsafe{} block",
-                    description,
-                    unsafe_fn_msg,
-                )
-                .span_label(source_info.span, description)
-                .note(note)
-                .emit();
-            }
-            UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
-                UNSAFE_OP_IN_UNSAFE_FN,
-                lint_root,
-                source_info.span,
-                |lint| {
-                    lint.build(&format!(
-                        "{} is unsafe and requires unsafe block (error E0133)",
-                        description,
-                    ))
-                    .span_label(source_info.span, description)
-                    .note(note)
-                    .emit();
-                },
-            ),
-        }
-    }
-
-    let (mut unsafe_used, mut unsafe_unused): (FxHashSet<_>, Vec<_>) = Default::default();
-    for &(block_id, is_used) in unsafe_blocks.iter() {
-        if is_used {
-            unsafe_used.insert(block_id);
-        } else {
-            unsafe_unused.push(block_id);
-        }
-    }
-    // The unused unsafe blocks might not be in source order; sort them so that the unused unsafe
-    // error messages are properly aligned and the issue-45107 and lint-unused-unsafe tests pass.
-    unsafe_unused.sort_by_cached_key(|hir_id| tcx.hir().span(*hir_id));
-
-    for &block_id in &unsafe_unused {
-        report_unused_unsafe(tcx, &unsafe_used, block_id);
-    }
-}
-
-fn unsafe_op_in_unsafe_fn_allowed(tcx: TyCtxt<'_>, id: HirId) -> bool {
-    tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, id).0 == Level::Allow
-}
diff --git a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
deleted file mode 100644
index 8ff0fae7686..00000000000
--- a/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-//! This module provides a pass to replacing the following statements with
-//! [`Nop`]s
-//!
-//!   - [`AscribeUserType`]
-//!   - [`FakeRead`]
-//!   - [`Assign`] statements with a [`Shallow`] borrow
-//!
-//! The `CleanFakeReadsAndBorrows` "pass" is actually implemented as two
-//! traversals (aka visits) of the input MIR. The first traversal,
-//! `DeleteAndRecordFakeReads`, deletes the fake reads and finds the
-//! temporaries read by [`ForMatchGuard`] reads, and `DeleteFakeBorrows`
-//! deletes the initialization of those temporaries.
-//!
-//! [`AscribeUserType`]: rustc_middle::mir::StatementKind::AscribeUserType
-//! [`Shallow`]: rustc_middle::mir::BorrowKind::Shallow
-//! [`FakeRead`]: rustc_middle::mir::StatementKind::FakeRead
-//! [`Assign`]: rustc_middle::mir::StatementKind::Assign
-//! [`ForMatchGuard`]: rustc_middle::mir::FakeReadCause::ForMatchGuard
-//! [`Nop`]: rustc_middle::mir::StatementKind::Nop
-
-use crate::transform::MirPass;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::{Body, BorrowKind, Location, Rvalue};
-use rustc_middle::mir::{Statement, StatementKind};
-use rustc_middle::ty::TyCtxt;
-
-pub struct CleanupNonCodegenStatements;
-
-pub struct DeleteNonCodegenStatements<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> MirPass<'tcx> for CleanupNonCodegenStatements {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let mut delete = DeleteNonCodegenStatements { tcx };
-        delete.visit_body(body);
-        body.user_type_annotations.raw.clear();
-
-        for decl in &mut body.local_decls {
-            decl.user_ty = None;
-        }
-    }
-}
-
-impl<'tcx> MutVisitor<'tcx> for DeleteNonCodegenStatements<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        match statement.kind {
-            StatementKind::AscribeUserType(..)
-            | StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
-            | StatementKind::FakeRead(..) => statement.make_nop(),
-            _ => (),
-        }
-        self.super_statement(statement, location);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/const_debuginfo.rs b/compiler/rustc_mir/src/transform/const_debuginfo.rs
deleted file mode 100644
index 3cdaf4c7dcd..00000000000
--- a/compiler/rustc_mir/src/transform/const_debuginfo.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-//! Finds locals which are assigned once to a const and unused except for debuginfo and converts
-//! their debuginfo to use the const directly, allowing the local to be removed.
-
-use rustc_middle::{
-    mir::{
-        visit::{PlaceContext, Visitor},
-        Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
-    },
-    ty::TyCtxt,
-};
-
-use crate::transform::MirPass;
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
-
-pub struct ConstDebugInfo;
-
-impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
-
-        trace!("running ConstDebugInfo on {:?}", body.source);
-
-        for (local, constant) in find_optimization_oportunities(body) {
-            for debuginfo in &mut body.var_debug_info {
-                if let VarDebugInfoContents::Place(p) = debuginfo.value {
-                    if p.local == local && p.projection.is_empty() {
-                        trace!(
-                            "changing debug info for {:?} from place {:?} to constant {:?}",
-                            debuginfo.name,
-                            p,
-                            constant
-                        );
-                        debuginfo.value = VarDebugInfoContents::Const(constant);
-                    }
-                }
-            }
-        }
-    }
-}
-
-struct LocalUseVisitor {
-    local_mutating_uses: IndexVec<Local, u8>,
-    local_assignment_locations: IndexVec<Local, Option<Location>>,
-}
-
-fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
-    let mut visitor = LocalUseVisitor {
-        local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
-        local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
-    };
-
-    visitor.visit_body(body);
-
-    let mut locals_to_debuginfo = BitSet::new_empty(body.local_decls.len());
-    for debuginfo in &body.var_debug_info {
-        if let VarDebugInfoContents::Place(p) = debuginfo.value {
-            if let Some(l) = p.as_local() {
-                locals_to_debuginfo.insert(l);
-            }
-        }
-    }
-
-    let mut eligable_locals = Vec::new();
-    for (local, mutating_uses) in visitor.local_mutating_uses.drain_enumerated(..) {
-        if mutating_uses != 1 || !locals_to_debuginfo.contains(local) {
-            continue;
-        }
-
-        if let Some(location) = visitor.local_assignment_locations[local] {
-            let bb = &body[location.block];
-
-            // The value is assigned as the result of a call, not a constant
-            if bb.statements.len() == location.statement_index {
-                continue;
-            }
-
-            if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(box c)))) =
-                &bb.statements[location.statement_index].kind
-            {
-                if let Some(local) = p.as_local() {
-                    eligable_locals.push((local, *c));
-                }
-            }
-        }
-    }
-
-    eligable_locals
-}
-
-impl<'tcx> Visitor<'tcx> for LocalUseVisitor {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) {
-        if context.is_mutating_use() {
-            self.local_mutating_uses[*local] = self.local_mutating_uses[*local].saturating_add(1);
-
-            if context.is_place_assignment() {
-                self.local_assignment_locations[*local] = Some(location);
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs
deleted file mode 100644
index ba10b54c5ae..00000000000
--- a/compiler/rustc_mir/src/transform/const_goto.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-//! This pass optimizes the following sequence
-//! ```rust,ignore (example)
-//! bb2: {
-//!     _2 = const true;
-//!     goto -> bb3;
-//! }
-//!
-//! bb3: {
-//!     switchInt(_2) -> [false: bb4, otherwise: bb5];
-//! }
-//! ```
-//! into
-//! ```rust,ignore (example)
-//! bb2: {
-//!     _2 = const true;
-//!     goto -> bb5;
-//! }
-//! ```
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::{mir::visit::Visitor, ty::ParamEnv};
-
-use super::simplify::{simplify_cfg, simplify_locals};
-
-pub struct ConstGoto;
-
-impl<'tcx> MirPass<'tcx> for ConstGoto {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
-        trace!("Running ConstGoto on {:?}", body.source);
-        let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-        let mut opt_finder =
-            ConstGotoOptimizationFinder { tcx, body, optimizations: vec![], param_env };
-        opt_finder.visit_body(body);
-        let should_simplify = !opt_finder.optimizations.is_empty();
-        for opt in opt_finder.optimizations {
-            let terminator = body.basic_blocks_mut()[opt.bb_with_goto].terminator_mut();
-            let new_goto = TerminatorKind::Goto { target: opt.target_to_use_in_goto };
-            debug!("SUCCESS: replacing `{:?}` with `{:?}`", terminator.kind, new_goto);
-            terminator.kind = new_goto;
-        }
-
-        // if we applied optimizations, we potentially have some cfg to cleanup to
-        // make it easier for further passes
-        if should_simplify {
-            simplify_cfg(tcx, body);
-            simplify_locals(body, tcx);
-        }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'a, 'tcx> {
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        let _: Option<_> = try {
-            let target = terminator.kind.as_goto()?;
-            // We only apply this optimization if the last statement is a const assignment
-            let last_statement = self.body.basic_blocks()[location.block].statements.last()?;
-
-            if let (place, Rvalue::Use(Operand::Constant(_const))) =
-                last_statement.kind.as_assign()?
-            {
-                // We found a constant being assigned to `place`.
-                // Now check that the target of this Goto switches on this place.
-                let target_bb = &self.body.basic_blocks()[target];
-
-                // FIXME(simonvandel): We are conservative here when we don't allow
-                // any statements in the target basic block.
-                // This could probably be relaxed to allow `StorageDead`s which could be
-                // copied to the predecessor of this block.
-                if !target_bb.statements.is_empty() {
-                    None?
-                }
-
-                let target_bb_terminator = target_bb.terminator();
-                let (discr, switch_ty, targets) = target_bb_terminator.kind.as_switch()?;
-                if discr.place() == Some(*place) {
-                    // We now know that the Switch matches on the const place, and it is statementless
-                    // Now find which value in the Switch matches the const value.
-                    let const_value =
-                        _const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?;
-                    let found_value_idx_option = targets
-                        .iter()
-                        .enumerate()
-                        .find(|(_, (value, _))| const_value == *value)
-                        .map(|(idx, _)| idx);
-
-                    let target_to_use_in_goto =
-                        if let Some(found_value_idx) = found_value_idx_option {
-                            targets.iter().nth(found_value_idx).unwrap().1
-                        } else {
-                            // If we did not find the const value in values, it must be the otherwise case
-                            targets.otherwise()
-                        };
-
-                    self.optimizations.push(OptimizationToApply {
-                        bb_with_goto: location.block,
-                        target_to_use_in_goto,
-                    });
-                }
-            }
-            Some(())
-        };
-
-        self.super_terminator(terminator, location);
-    }
-}
-
-struct OptimizationToApply {
-    bb_with_goto: BasicBlock,
-    target_to_use_in_goto: BasicBlock,
-}
-
-pub struct ConstGotoOptimizationFinder<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    optimizations: Vec<OptimizationToApply>,
-}
diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs
deleted file mode 100644
index 71c07be4c6d..00000000000
--- a/compiler/rustc_mir/src/transform/const_prop.rs
+++ /dev/null
@@ -1,1312 +0,0 @@
-//! Propagates constants for early reporting of statically known
-//! assertion failures
-
-use std::cell::Cell;
-
-use rustc_ast::Mutability;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_hir::def::DefKind;
-use rustc_hir::HirId;
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
-use rustc_middle::mir::visit::{
-    MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
-};
-use rustc_middle::mir::{
-    AssertKind, BasicBlock, BinOp, Body, Constant, ConstantKind, Local, LocalDecl, LocalKind,
-    Location, Operand, Place, Rvalue, SourceInfo, SourceScope, SourceScopeData, Statement,
-    StatementKind, Terminator, TerminatorKind, UnOp, RETURN_PLACE,
-};
-use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::subst::{InternalSubsts, Subst};
-use rustc_middle::ty::{
-    self, ConstInt, ConstKind, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeFoldable,
-};
-use rustc_session::lint;
-use rustc_span::{def_id::DefId, Span};
-use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
-use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
-
-use crate::const_eval::ConstEvalErr;
-use crate::interpret::{
-    self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy,
-    Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, MemoryKind, OpTy,
-    Operand as InterpOperand, PlaceTy, Scalar, ScalarMaybeUninit, StackPopCleanup, StackPopUnwind,
-};
-use crate::transform::MirPass;
-
-/// 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
-/// Severely regress performance.
-const MAX_ALLOC_LIMIT: u64 = 1024;
-
-/// Macro for machine-specific `InterpError` without allocation.
-/// (These will never be shown to the user, but they help diagnose ICEs.)
-macro_rules! throw_machine_stop_str {
-    ($($tt:tt)*) => {{
-        // We make a new local type for it. The type itself does not carry any information,
-        // but its vtable (for the `MachineStopType` trait) does.
-        struct Zst;
-        // Printing this type shows the desired string.
-        impl std::fmt::Display for Zst {
-            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                write!(f, $($tt)*)
-            }
-        }
-        impl rustc_middle::mir::interpret::MachineStopType for Zst {}
-        throw_machine_stop!(Zst)
-    }};
-}
-
-pub struct ConstProp;
-
-impl<'tcx> MirPass<'tcx> for ConstProp {
-    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() {
-            return;
-        }
-
-        use rustc_middle::hir::map::blocks::FnLikeNode;
-        let def_id = body.source.def_id().expect_local();
-        let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
-
-        let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
-        let is_assoc_const = tcx.def_kind(def_id.to_def_id()) == DefKind::AssocConst;
-
-        // Only run const prop on functions, methods, closures and associated constants
-        if !is_fn_like && !is_assoc_const {
-            // skip anon_const/statics/consts because they'll be evaluated by miri anyway
-            trace!("ConstProp skipped for {:?}", def_id);
-            return;
-        }
-
-        let is_generator = tcx.type_of(def_id.to_def_id()).is_generator();
-        // FIXME(welseywiser) const prop doesn't work on generators because of query cycles
-        // computing their layout.
-        if is_generator {
-            trace!("ConstProp skipped for generator {:?}", def_id);
-            return;
-        }
-
-        // Check if it's even possible to satisfy the 'where' clauses
-        // for this item.
-        // This branch will never be taken for any normal function.
-        // However, it's possible to `#!feature(trivial_bounds)]` to write
-        // a function with impossible to satisfy clauses, e.g.:
-        // `fn foo() where String: Copy {}`
-        //
-        // We don't usually need to worry about this kind of case,
-        // since we would get a compilation error if the user tried
-        // to call it. However, since we can do const propagation
-        // even without any calls to the function, we need to make
-        // sure that it even makes sense to try to evaluate the body.
-        // If there are unsatisfiable where clauses, then all bets are
-        // off, and we just give up.
-        //
-        // We manually filter the predicates, skipping anything that's not
-        // "global". We are in a potentially generic context
-        // (e.g. we are evaluating a function without substituting generic
-        // parameters, so this filtering serves two purposes:
-        //
-        // 1. We skip evaluating any predicates that we would
-        // never be able prove are unsatisfiable (e.g. `<T as Foo>`
-        // 2. We avoid trying to normalize predicates involving generic
-        // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
-        // the normalization code (leading to cycle errors), since
-        // it's usually never invoked in this way.
-        let predicates = tcx
-            .predicates_of(def_id.to_def_id())
-            .predicates
-            .iter()
-            .filter_map(|(p, _)| if p.is_global(tcx) { Some(*p) } else { None });
-        if traits::impossible_predicates(
-            tcx,
-            traits::elaborate_predicates(tcx, predicates).map(|o| o.predicate).collect(),
-        ) {
-            trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
-            return;
-        }
-
-        trace!("ConstProp starting for {:?}", def_id);
-
-        let dummy_body = &Body::new(
-            tcx,
-            body.source,
-            body.basic_blocks().clone(),
-            body.source_scopes.clone(),
-            body.local_decls.clone(),
-            Default::default(),
-            body.arg_count,
-            Default::default(),
-            body.span,
-            body.generator_kind(),
-        );
-
-        // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
-        // constants, instead of just checking for const-folding succeeding.
-        // That would require a uniform one-def no-mutation analysis
-        // and RPO (or recursing when needing the value of a local).
-        let mut optimization_finder = ConstPropagator::new(body, dummy_body, tcx);
-        optimization_finder.visit_body(body);
-
-        trace!("ConstProp done for {:?}", def_id);
-    }
-}
-
-struct ConstPropMachine<'mir, 'tcx> {
-    /// The virtual call stack.
-    stack: Vec<Frame<'mir, 'tcx>>,
-    /// `OnlyInsideOwnBlock` locals that were written in the current block get erased at the end.
-    written_only_inside_own_block_locals: FxHashSet<Local>,
-    /// Locals that need to be cleared after every block terminates.
-    only_propagate_inside_block_locals: BitSet<Local>,
-    can_const_prop: IndexVec<Local, ConstPropMode>,
-}
-
-impl<'mir, 'tcx> ConstPropMachine<'mir, 'tcx> {
-    fn new(
-        only_propagate_inside_block_locals: BitSet<Local>,
-        can_const_prop: IndexVec<Local, ConstPropMode>,
-    ) -> Self {
-        Self {
-            stack: Vec::new(),
-            written_only_inside_own_block_locals: Default::default(),
-            only_propagate_inside_block_locals,
-            can_const_prop,
-        }
-    }
-}
-
-impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> {
-    compile_time_machine!(<'mir, 'tcx>);
-    const PANIC_ON_ALLOC_FAIL: bool = true; // all allocations are small (see `MAX_ALLOC_LIMIT`)
-
-    type MemoryKind = !;
-
-    type MemoryExtra = ();
-
-    fn load_mir(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::InstanceDef<'tcx>,
-    ) -> InterpResult<'tcx, &'tcx Body<'tcx>> {
-        throw_machine_stop_str!("calling functions isn't supported in ConstProp")
-    }
-
-    fn find_mir_or_eval_fn(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _abi: Abi,
-        _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> {
-        Ok(None)
-    }
-
-    fn call_intrinsic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _instance: ty::Instance<'tcx>,
-        _args: &[OpTy<'tcx>],
-        _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>,
-        _unwind: StackPopUnwind,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp")
-    }
-
-    fn assert_panic(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _msg: &rustc_middle::mir::AssertMessage<'tcx>,
-        _unwind: Option<rustc_middle::mir::BasicBlock>,
-    ) -> InterpResult<'tcx> {
-        bug!("panics terminators are not evaluated in ConstProp")
-    }
-
-    fn binary_ptr_op(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        _bin_op: BinOp,
-        _left: &ImmTy<'tcx>,
-        _right: &ImmTy<'tcx>,
-    ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> {
-        // We can't do this because aliasing of memory can differ between const eval and llvm
-        throw_machine_stop_str!("pointer arithmetic or comparisons aren't supported in ConstProp")
-    }
-
-    fn box_alloc(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        _dest: &PlaceTy<'tcx>,
-    ) -> InterpResult<'tcx> {
-        throw_machine_stop_str!("can't const prop heap allocations")
-    }
-
-    fn access_local(
-        _ecx: &InterpCx<'mir, 'tcx, Self>,
-        frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>,
-        local: Local,
-    ) -> InterpResult<'tcx, InterpOperand<Self::PointerTag>> {
-        let l = &frame.locals[local];
-
-        if l.value == LocalValue::Uninitialized {
-            throw_machine_stop_str!("tried to access an uninitialized local")
-        }
-
-        l.access()
-    }
-
-    fn access_local_mut<'a>(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-        frame: usize,
-        local: Local,
-    ) -> InterpResult<'tcx, Result<&'a mut LocalValue<Self::PointerTag>, MemPlace<Self::PointerTag>>>
-    {
-        if ecx.machine.can_const_prop[local] == ConstPropMode::NoPropagation {
-            throw_machine_stop_str!("tried to write to a local that is marked as not propagatable")
-        }
-        if frame == 0 && ecx.machine.only_propagate_inside_block_locals.contains(local) {
-            trace!(
-                "mutating local {:?} which is restricted to its block. \
-                Will remove it from const-prop after block is finished.",
-                local
-            );
-            ecx.machine.written_only_inside_own_block_locals.insert(local);
-        }
-        ecx.machine.stack[frame].locals[local].access_mut()
-    }
-
-    fn before_access_global(
-        _memory_extra: &(),
-        _alloc_id: AllocId,
-        allocation: &Allocation<Self::PointerTag, Self::AllocExtra>,
-        _static_def_id: Option<DefId>,
-        is_write: bool,
-    ) -> InterpResult<'tcx> {
-        if is_write {
-            throw_machine_stop_str!("can't write to global");
-        }
-        // If the static allocation is mutable, then we can't const prop it as its content
-        // might be different at runtime.
-        if allocation.mutability == Mutability::Mut {
-            throw_machine_stop_str!("can't access mutable globals in ConstProp");
-        }
-
-        Ok(())
-    }
-
-    #[inline(always)]
-    fn init_frame_extra(
-        _ecx: &mut InterpCx<'mir, 'tcx, Self>,
-        frame: Frame<'mir, 'tcx>,
-    ) -> InterpResult<'tcx, Frame<'mir, 'tcx>> {
-        Ok(frame)
-    }
-
-    #[inline(always)]
-    fn stack(
-        ecx: &'a InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] {
-        &ecx.machine.stack
-    }
-
-    #[inline(always)]
-    fn stack_mut(
-        ecx: &'a mut InterpCx<'mir, 'tcx, Self>,
-    ) -> &'a mut Vec<Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>> {
-        &mut ecx.machine.stack
-    }
-}
-
-/// Finds optimization opportunities on the MIR.
-struct ConstPropagator<'mir, 'tcx> {
-    ecx: InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>,
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    // FIXME(eddyb) avoid cloning these two fields more than once,
-    // by accessing them through `ecx` instead.
-    source_scopes: IndexVec<SourceScope, SourceScopeData<'tcx>>,
-    local_decls: IndexVec<Local, LocalDecl<'tcx>>,
-    // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
-    // the last known `SourceInfo` here and just keep revisiting it.
-    source_info: Option<SourceInfo>,
-}
-
-impl<'mir, 'tcx> LayoutOfHelpers<'tcx> for ConstPropagator<'mir, 'tcx> {
-    type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
-
-    #[inline]
-    fn handle_layout_err(&self, err: LayoutError<'tcx>, _: Span, _: Ty<'tcx>) -> LayoutError<'tcx> {
-        err
-    }
-}
-
-impl<'mir, 'tcx> HasDataLayout for ConstPropagator<'mir, 'tcx> {
-    #[inline]
-    fn data_layout(&self) -> &TargetDataLayout {
-        &self.tcx.data_layout
-    }
-}
-
-impl<'mir, 'tcx> ty::layout::HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
-    #[inline]
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-}
-
-impl<'mir, 'tcx> ty::layout::HasParamEnv<'tcx> for ConstPropagator<'mir, 'tcx> {
-    #[inline]
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.param_env
-    }
-}
-
-impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
-    fn new(
-        body: &Body<'tcx>,
-        dummy_body: &'mir Body<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ConstPropagator<'mir, 'tcx> {
-        let def_id = body.source.def_id();
-        let substs = &InternalSubsts::identity_for_item(tcx, def_id);
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
-        let span = tcx.def_span(def_id);
-        // FIXME: `CanConstProp::check` computes the layout of all locals, return those layouts
-        // so we can write them to `ecx.frame_mut().locals.layout, reducing the duplication in
-        // `layout_of` query invocations.
-        let can_const_prop = CanConstProp::check(tcx, param_env, body);
-        let mut only_propagate_inside_block_locals = BitSet::new_empty(can_const_prop.len());
-        for (l, mode) in can_const_prop.iter_enumerated() {
-            if *mode == ConstPropMode::OnlyInsideOwnBlock {
-                only_propagate_inside_block_locals.insert(l);
-            }
-        }
-        let mut ecx = InterpCx::new(
-            tcx,
-            span,
-            param_env,
-            ConstPropMachine::new(only_propagate_inside_block_locals, can_const_prop),
-            (),
-        );
-
-        let ret = ecx
-            .layout_of(body.return_ty().subst(tcx, substs))
-            .ok()
-            // Don't bother allocating memory for ZST types which have no values
-            // or for large values.
-            .filter(|ret_layout| {
-                !ret_layout.is_zst() && ret_layout.size < Size::from_bytes(MAX_ALLOC_LIMIT)
-            })
-            .map(|ret_layout| {
-                ecx.allocate(ret_layout, MemoryKind::Stack)
-                    .expect("couldn't perform small allocation")
-                    .into()
-            });
-
-        ecx.push_stack_frame(
-            Instance::new(def_id, substs),
-            dummy_body,
-            ret.as_ref(),
-            StackPopCleanup::None { cleanup: false },
-        )
-        .expect("failed to push initial stack frame");
-
-        ConstPropagator {
-            ecx,
-            tcx,
-            param_env,
-            // FIXME(eddyb) avoid cloning these two fields more than once,
-            // by accessing them through `ecx` instead.
-            source_scopes: body.source_scopes.clone(),
-            //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
-            local_decls: body.local_decls.clone(),
-            source_info: None,
-        }
-    }
-
-    fn get_const(&self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
-        let op = match self.ecx.eval_place_to_op(place, None) {
-            Ok(op) => op,
-            Err(e) => {
-                trace!("get_const failed: {}", e);
-                return None;
-            }
-        };
-
-        // Try to read the local as an immediate so that if it is representable as a scalar, we can
-        // handle it as such, but otherwise, just return the value as is.
-        Some(match self.ecx.try_read_immediate(&op) {
-            Ok(Ok(imm)) => imm.into(),
-            _ => op,
-        })
-    }
-
-    /// Remove `local` from the pool of `Locals`. Allows writing to them,
-    /// but not reading from them anymore.
-    fn remove_const(ecx: &mut InterpCx<'mir, 'tcx, ConstPropMachine<'mir, 'tcx>>, local: Local) {
-        ecx.frame_mut().locals[local] =
-            LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) };
-    }
-
-    fn lint_root(&self, source_info: SourceInfo) -> Option<HirId> {
-        source_info.scope.lint_root(&self.source_scopes)
-    }
-
-    fn use_ecx<F, T>(&mut self, f: F) -> Option<T>
-    where
-        F: FnOnce(&mut Self) -> InterpResult<'tcx, T>,
-    {
-        match f(self) {
-            Ok(val) => Some(val),
-            Err(error) => {
-                trace!("InterpCx operation failed: {:?}", error);
-                // Some errors shouldn't come up because creating them causes
-                // an allocation, which we should avoid. When that happens,
-                // dedicated error variants should be introduced instead.
-                assert!(
-                    !error.kind().formatted_string(),
-                    "const-prop encountered formatting error: {}",
-                    error
-                );
-                None
-            }
-        }
-    }
-
-    /// Returns the value, if any, of evaluating `c`.
-    fn eval_constant(&mut self, c: &Constant<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
-        // FIXME we need to revisit this for #67176
-        if c.definitely_needs_subst(self.tcx) {
-            return None;
-        }
-
-        match self.ecx.mir_const_to_op(&c.literal, None) {
-            Ok(op) => Some(op),
-            Err(error) => {
-                let tcx = self.ecx.tcx.at(c.span);
-                let err = ConstEvalErr::new(&self.ecx, error, Some(c.span));
-                if let Some(lint_root) = self.lint_root(source_info) {
-                    let lint_only = match c.literal {
-                        ConstantKind::Ty(ct) => match ct.val {
-                            // Promoteds must lint and not error as the user didn't ask for them
-                            ConstKind::Unevaluated(ty::Unevaluated {
-                                def: _,
-                                substs_: _,
-                                promoted: Some(_),
-                            }) => true,
-                            // Out of backwards compatibility we cannot report hard errors in unused
-                            // generic functions using associated constants of the generic parameters.
-                            _ => c.literal.definitely_needs_subst(*tcx),
-                        },
-                        ConstantKind::Val(_, ty) => ty.definitely_needs_subst(*tcx),
-                    };
-                    if lint_only {
-                        // Out of backwards compatibility we cannot report hard errors in unused
-                        // generic functions using associated constants of the generic parameters.
-                        err.report_as_lint(tcx, "erroneous constant used", lint_root, Some(c.span));
-                    } else {
-                        err.report_as_error(tcx, "erroneous constant used");
-                    }
-                } else {
-                    err.report_as_error(tcx, "erroneous constant used");
-                }
-                None
-            }
-        }
-    }
-
-    /// Returns the value, if any, of evaluating `place`.
-    fn eval_place(&mut self, place: Place<'tcx>) -> Option<OpTy<'tcx>> {
-        trace!("eval_place(place={:?})", place);
-        self.use_ecx(|this| this.ecx.eval_place_to_op(place, None))
-    }
-
-    /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
-    /// or `eval_place`, depending on the variant of `Operand` used.
-    fn eval_operand(&mut self, op: &Operand<'tcx>, source_info: SourceInfo) -> Option<OpTy<'tcx>> {
-        match *op {
-            Operand::Constant(ref c) => self.eval_constant(c, source_info),
-            Operand::Move(place) | Operand::Copy(place) => self.eval_place(place),
-        }
-    }
-
-    fn report_assert_as_lint(
-        &self,
-        lint: &'static lint::Lint,
-        source_info: SourceInfo,
-        message: &'static str,
-        panic: AssertKind<impl std::fmt::Debug>,
-    ) {
-        if let Some(lint_root) = self.lint_root(source_info) {
-            self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
-                let mut err = lint.build(message);
-                err.span_label(source_info.span, format!("{:?}", panic));
-                err.emit()
-            });
-        }
-    }
-
-    fn check_unary_op(
-        &mut self,
-        op: UnOp,
-        arg: &Operand<'tcx>,
-        source_info: SourceInfo,
-    ) -> Option<()> {
-        if let (val, true) = self.use_ecx(|this| {
-            let val = this.ecx.read_immediate(&this.ecx.eval_operand(arg, None)?)?;
-            let (_res, overflow, _ty) = this.ecx.overflowing_unary_op(op, &val)?;
-            Ok((val, overflow))
-        })? {
-            // `AssertKind` only has an `OverflowNeg` variant, so make sure that is
-            // appropriate to use.
-            assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
-            self.report_assert_as_lint(
-                lint::builtin::ARITHMETIC_OVERFLOW,
-                source_info,
-                "this arithmetic operation will overflow",
-                AssertKind::OverflowNeg(val.to_const_int()),
-            );
-            return None;
-        }
-
-        Some(())
-    }
-
-    fn check_binary_op(
-        &mut self,
-        op: BinOp,
-        left: &Operand<'tcx>,
-        right: &Operand<'tcx>,
-        source_info: SourceInfo,
-    ) -> Option<()> {
-        let r = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(right, None)?));
-        let l = self.use_ecx(|this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
-        // Check for exceeding shifts *even if* we cannot evaluate the LHS.
-        if op == BinOp::Shr || op == BinOp::Shl {
-            let r = r?;
-            // We need the type of the LHS. We cannot use `place_layout` as that is the type
-            // of the result, which for checked binops is not the same!
-            let left_ty = left.ty(&self.local_decls, self.tcx);
-            let left_size = self.ecx.layout_of(left_ty).ok()?.size;
-            let right_size = r.layout.size;
-            let r_bits = r.to_scalar().ok();
-            let r_bits = r_bits.and_then(|r| r.to_bits(right_size).ok());
-            if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
-                debug!("check_binary_op: reporting assert for {:?}", source_info);
-                self.report_assert_as_lint(
-                    lint::builtin::ARITHMETIC_OVERFLOW,
-                    source_info,
-                    "this arithmetic operation will overflow",
-                    AssertKind::Overflow(
-                        op,
-                        match l {
-                            Some(l) => l.to_const_int(),
-                            // Invent a dummy value, the diagnostic ignores it anyway
-                            None => ConstInt::new(
-                                ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
-                                left_ty.is_signed(),
-                                left_ty.is_ptr_sized_integral(),
-                            ),
-                        },
-                        r.to_const_int(),
-                    ),
-                );
-                return None;
-            }
-        }
-
-        if let (Some(l), Some(r)) = (&l, &r) {
-            // The remaining operators are handled through `overflowing_binary_op`.
-            if self.use_ecx(|this| {
-                let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, l, r)?;
-                Ok(overflow)
-            })? {
-                self.report_assert_as_lint(
-                    lint::builtin::ARITHMETIC_OVERFLOW,
-                    source_info,
-                    "this arithmetic operation will overflow",
-                    AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
-                );
-                return None;
-            }
-        }
-        Some(())
-    }
-
-    fn propagate_operand(&mut self, operand: &mut Operand<'tcx>) {
-        match *operand {
-            Operand::Copy(l) | Operand::Move(l) => {
-                if let Some(value) = self.get_const(l) {
-                    if self.should_const_prop(&value) {
-                        // FIXME(felix91gr): this code only handles `Scalar` cases.
-                        // For now, we're not handling `ScalarPair` cases because
-                        // doing so here would require a lot of code duplication.
-                        // We should hopefully generalize `Operand` handling into a fn,
-                        // and use it to do const-prop here and everywhere else
-                        // where it makes sense.
-                        if let interpret::Operand::Immediate(interpret::Immediate::Scalar(
-                            ScalarMaybeUninit::Scalar(scalar),
-                        )) = *value
-                        {
-                            *operand = self.operand_from_scalar(
-                                scalar,
-                                value.layout.ty,
-                                self.source_info.unwrap().span,
-                            );
-                        }
-                    }
-                }
-            }
-            Operand::Constant(_) => (),
-        }
-    }
-
-    fn const_prop(
-        &mut self,
-        rvalue: &Rvalue<'tcx>,
-        source_info: SourceInfo,
-        place: Place<'tcx>,
-    ) -> Option<()> {
-        // Perform any special handling for specific Rvalue types.
-        // Generally, checks here fall into one of two categories:
-        //   1. Additional checking to provide useful lints to the user
-        //        - In this case, we will do some validation and then fall through to the
-        //          end of the function which evals the assignment.
-        //   2. Working around bugs in other parts of the compiler
-        //        - In this case, we'll return `None` from this function to stop evaluation.
-        match rvalue {
-            // Additional checking: give lints to the user if an overflow would occur.
-            // We do this here and not in the `Assert` terminator as that terminator is
-            // only sometimes emitted (overflow checks can be disabled), but we want to always
-            // lint.
-            Rvalue::UnaryOp(op, arg) => {
-                trace!("checking UnaryOp(op = {:?}, arg = {:?})", op, arg);
-                self.check_unary_op(*op, arg, source_info)?;
-            }
-            Rvalue::BinaryOp(op, box (left, right)) => {
-                trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
-                self.check_binary_op(*op, left, right, source_info)?;
-            }
-            Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                trace!(
-                    "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})",
-                    op,
-                    left,
-                    right
-                );
-                self.check_binary_op(*op, left, right, source_info)?;
-            }
-
-            // Do not try creating references (#67862)
-            Rvalue::AddressOf(_, place) | Rvalue::Ref(_, _, place) => {
-                trace!("skipping AddressOf | Ref for {:?}", place);
-
-                // This may be creating mutable references or immutable references to cells.
-                // If that happens, the pointed to value could be mutated via that reference.
-                // Since we aren't tracking references, the const propagator loses track of what
-                // value the local has right now.
-                // Thus, all locals that have their reference taken
-                // must not take part in propagation.
-                Self::remove_const(&mut self.ecx, place.local);
-
-                return None;
-            }
-            Rvalue::ThreadLocalRef(def_id) => {
-                trace!("skipping ThreadLocalRef({:?})", def_id);
-
-                return None;
-            }
-
-            // There's no other checking to do at this time.
-            Rvalue::Aggregate(..)
-            | Rvalue::Use(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::Cast(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::NullaryOp(..) => {}
-        }
-
-        // FIXME we need to revisit this for #67176
-        if rvalue.definitely_needs_subst(self.tcx) {
-            return None;
-        }
-
-        if self.tcx.sess.mir_opt_level() >= 4 {
-            self.eval_rvalue_with_identities(rvalue, place)
-        } else {
-            self.use_ecx(|this| this.ecx.eval_rvalue_into_place(rvalue, place))
-        }
-    }
-
-    // Attempt to use albegraic identities to eliminate constant expressions
-    fn eval_rvalue_with_identities(
-        &mut self,
-        rvalue: &Rvalue<'tcx>,
-        place: Place<'tcx>,
-    ) -> Option<()> {
-        self.use_ecx(|this| {
-            match rvalue {
-                Rvalue::BinaryOp(op, box (left, right))
-                | Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                    let l = this.ecx.eval_operand(left, None);
-                    let r = this.ecx.eval_operand(right, None);
-
-                    let const_arg = match (l, r) {
-                        (Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
-                        (Err(e), Err(_)) => return Err(e),
-                        (Ok(_), Ok(_)) => {
-                            this.ecx.eval_rvalue_into_place(rvalue, place)?;
-                            return Ok(());
-                        }
-                    };
-
-                    let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
-                    let dest = this.ecx.eval_place(place)?;
-
-                    match op {
-                        BinOp::BitAnd => {
-                            if arg_value == 0 {
-                                this.ecx.write_immediate(*const_arg, &dest)?;
-                            }
-                        }
-                        BinOp::BitOr => {
-                            if arg_value == const_arg.layout.size.truncate(u128::MAX)
-                                || (const_arg.layout.ty.is_bool() && arg_value == 1)
-                            {
-                                this.ecx.write_immediate(*const_arg, &dest)?;
-                            }
-                        }
-                        BinOp::Mul => {
-                            if const_arg.layout.ty.is_integral() && arg_value == 0 {
-                                if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
-                                    let val = Immediate::ScalarPair(
-                                        const_arg.to_scalar()?.into(),
-                                        Scalar::from_bool(false).into(),
-                                    );
-                                    this.ecx.write_immediate(val, &dest)?;
-                                } else {
-                                    this.ecx.write_immediate(*const_arg, &dest)?;
-                                }
-                            }
-                        }
-                        _ => {
-                            this.ecx.eval_rvalue_into_place(rvalue, place)?;
-                        }
-                    }
-                }
-                _ => {
-                    this.ecx.eval_rvalue_into_place(rvalue, place)?;
-                }
-            }
-
-            Ok(())
-        })
-    }
-
-    /// Creates a new `Operand::Constant` from a `Scalar` value
-    fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Operand<'tcx> {
-        Operand::Constant(Box::new(Constant {
-            span,
-            user_ty: None,
-            literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(),
-        }))
-    }
-
-    fn replace_with_const(
-        &mut self,
-        rval: &mut Rvalue<'tcx>,
-        value: &OpTy<'tcx>,
-        source_info: SourceInfo,
-    ) {
-        if let Rvalue::Use(Operand::Constant(c)) = rval {
-            match c.literal {
-                ConstantKind::Ty(c) if matches!(c.val, ConstKind::Unevaluated(..)) => {}
-                _ => {
-                    trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
-                    return;
-                }
-            }
-        }
-
-        trace!("attempting to replace {:?} with {:?}", rval, value);
-        if let Err(e) = self.ecx.const_validate_operand(
-            value,
-            vec![],
-            // FIXME: is ref tracking too expensive?
-            // FIXME: what is the point of ref tracking if we do not even check the tracked refs?
-            &mut interpret::RefTracking::empty(),
-            CtfeValidationMode::Regular,
-        ) {
-            trace!("validation error, attempt failed: {:?}", e);
-            return;
-        }
-
-        // FIXME> figure out what to do when try_read_immediate fails
-        let imm = self.use_ecx(|this| this.ecx.try_read_immediate(value));
-
-        if let Some(Ok(imm)) = imm {
-            match *imm {
-                interpret::Immediate::Scalar(ScalarMaybeUninit::Scalar(scalar)) => {
-                    *rval = Rvalue::Use(self.operand_from_scalar(
-                        scalar,
-                        value.layout.ty,
-                        source_info.span,
-                    ));
-                }
-                Immediate::ScalarPair(
-                    ScalarMaybeUninit::Scalar(_),
-                    ScalarMaybeUninit::Scalar(_),
-                ) => {
-                    // Found a value represented as a pair. For now only do const-prop if the type
-                    // of `rvalue` is also a tuple with two scalars.
-                    // FIXME: enable the general case stated above ^.
-                    let ty = &value.layout.ty;
-                    // Only do it for tuples
-                    if let ty::Tuple(substs) = ty.kind() {
-                        // Only do it if tuple is also a pair with two scalars
-                        if substs.len() == 2 {
-                            let alloc = self.use_ecx(|this| {
-                                let ty1 = substs[0].expect_ty();
-                                let ty2 = substs[1].expect_ty();
-                                let ty_is_scalar = |ty| {
-                                    this.ecx.layout_of(ty).ok().map(|layout| layout.abi.is_scalar())
-                                        == Some(true)
-                                };
-                                if ty_is_scalar(ty1) && ty_is_scalar(ty2) {
-                                    let alloc = this
-                                        .ecx
-                                        .intern_with_temp_alloc(value.layout, |ecx, dest| {
-                                            ecx.write_immediate(*imm, dest)
-                                        })
-                                        .unwrap();
-                                    Ok(Some(alloc))
-                                } else {
-                                    Ok(None)
-                                }
-                            });
-
-                            if let Some(Some(alloc)) = alloc {
-                                // Assign entire constant in a single statement.
-                                // We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
-                                *rval = Rvalue::Use(Operand::Constant(Box::new(Constant {
-                                    span: source_info.span,
-                                    user_ty: None,
-                                    literal: self
-                                        .ecx
-                                        .tcx
-                                        .mk_const(ty::Const {
-                                            ty,
-                                            val: ty::ConstKind::Value(ConstValue::ByRef {
-                                                alloc,
-                                                offset: Size::ZERO,
-                                            }),
-                                        })
-                                        .into(),
-                                })));
-                            }
-                        }
-                    }
-                }
-                // Scalars or scalar pairs that contain undef values are assumed to not have
-                // successfully evaluated and are thus not propagated.
-                _ => {}
-            }
-        }
-    }
-
-    /// Returns `true` if and only if this `op` should be const-propagated into.
-    fn should_const_prop(&mut self, op: &OpTy<'tcx>) -> bool {
-        let mir_opt_level = self.tcx.sess.mir_opt_level();
-
-        if mir_opt_level == 0 {
-            return false;
-        }
-
-        if !self.tcx.consider_optimizing(|| format!("ConstantPropagation - OpTy: {:?}", op)) {
-            return false;
-        }
-
-        match **op {
-            interpret::Operand::Immediate(Immediate::Scalar(ScalarMaybeUninit::Scalar(s))) => {
-                s.try_to_int().is_ok()
-            }
-            interpret::Operand::Immediate(Immediate::ScalarPair(
-                ScalarMaybeUninit::Scalar(l),
-                ScalarMaybeUninit::Scalar(r),
-            )) => l.try_to_int().is_ok() && r.try_to_int().is_ok(),
-            _ => false,
-        }
-    }
-}
-
-/// The mode that `ConstProp` is allowed to run in for a given `Local`.
-#[derive(Clone, Copy, Debug, PartialEq)]
-enum ConstPropMode {
-    /// The `Local` can be propagated into and reads of this `Local` can also be propagated.
-    FullConstProp,
-    /// The `Local` can only be propagated into and from its own block.
-    OnlyInsideOwnBlock,
-    /// The `Local` can be propagated into but reads cannot be propagated.
-    OnlyPropagateInto,
-    /// The `Local` cannot be part of propagation at all. Any statement
-    /// referencing it either for reading or writing will not get propagated.
-    NoPropagation,
-}
-
-struct CanConstProp {
-    can_const_prop: IndexVec<Local, ConstPropMode>,
-    // False at the beginning. Once set, no more assignments are allowed to that local.
-    found_assignment: BitSet<Local>,
-    // Cache of locals' information
-    local_kinds: IndexVec<Local, LocalKind>,
-}
-
-impl CanConstProp {
-    /// Returns true if `local` can be propagated
-    fn check(
-        tcx: TyCtxt<'tcx>,
-        param_env: ParamEnv<'tcx>,
-        body: &Body<'tcx>,
-    ) -> IndexVec<Local, ConstPropMode> {
-        let mut cpv = CanConstProp {
-            can_const_prop: IndexVec::from_elem(ConstPropMode::FullConstProp, &body.local_decls),
-            found_assignment: BitSet::new_empty(body.local_decls.len()),
-            local_kinds: IndexVec::from_fn_n(
-                |local| body.local_kind(local),
-                body.local_decls.len(),
-            ),
-        };
-        for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
-            let ty = body.local_decls[local].ty;
-            match tcx.layout_of(param_env.and(ty)) {
-                Ok(layout) if layout.size < Size::from_bytes(MAX_ALLOC_LIMIT) => {}
-                // Either the layout fails to compute, then we can't use this local anyway
-                // or the local is too large, then we don't want to.
-                _ => {
-                    *val = ConstPropMode::NoPropagation;
-                    continue;
-                }
-            }
-            // Cannot use args at all
-            // Cannot use locals because if x < y { y - x } else { x - y } would
-            //        lint for x != y
-            // FIXME(oli-obk): lint variables until they are used in a condition
-            // FIXME(oli-obk): lint if return value is constant
-            if cpv.local_kinds[local] == LocalKind::Arg {
-                *val = ConstPropMode::OnlyPropagateInto;
-                trace!(
-                    "local {:?} can't be const propagated because it's a function argument",
-                    local
-                );
-            } else if cpv.local_kinds[local] == LocalKind::Var {
-                *val = ConstPropMode::OnlyInsideOwnBlock;
-                trace!(
-                    "local {:?} will only be propagated inside its block, because it's a user variable",
-                    local
-                );
-            }
-        }
-        cpv.visit_body(&body);
-        cpv.can_const_prop
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for CanConstProp {
-    fn visit_local(&mut self, &local: &Local, context: PlaceContext, _: Location) {
-        use rustc_middle::mir::visit::PlaceContext::*;
-        match context {
-            // Projections are fine, because `&mut foo.x` will be caught by
-            // `MutatingUseContext::Borrow` elsewhere.
-            MutatingUse(MutatingUseContext::Projection)
-            // These are just stores, where the storing is not propagatable, but there may be later
-            // mutations of the same local via `Store`
-            | MutatingUse(MutatingUseContext::Call)
-            // Actual store that can possibly even propagate a value
-            | MutatingUse(MutatingUseContext::Store) => {
-                if !self.found_assignment.insert(local) {
-                    match &mut self.can_const_prop[local] {
-                        // If the local can only get propagated in its own block, then we don't have
-                        // to worry about multiple assignments, as we'll nuke the const state at the
-                        // end of the block anyway, and inside the block we overwrite previous
-                        // states as applicable.
-                        ConstPropMode::OnlyInsideOwnBlock => {}
-                        ConstPropMode::NoPropagation => {}
-                        ConstPropMode::OnlyPropagateInto => {}
-                        other @ ConstPropMode::FullConstProp => {
-                            trace!(
-                                "local {:?} can't be propagated because of multiple assignments. Previous state: {:?}",
-                                local, other,
-                            );
-                            *other = ConstPropMode::OnlyInsideOwnBlock;
-                        }
-                    }
-                }
-            }
-            // Reading constants is allowed an arbitrary number of times
-            NonMutatingUse(NonMutatingUseContext::Copy)
-            | NonMutatingUse(NonMutatingUseContext::Move)
-            | NonMutatingUse(NonMutatingUseContext::Inspect)
-            | NonMutatingUse(NonMutatingUseContext::Projection)
-            | NonUse(_) => {}
-
-            // These could be propagated with a smarter analysis or just some careful thinking about
-            // whether they'd be fine right now.
-            MutatingUse(MutatingUseContext::AsmOutput)
-            | MutatingUse(MutatingUseContext::Yield)
-            | MutatingUse(MutatingUseContext::Drop)
-            | MutatingUse(MutatingUseContext::Retag)
-            // These can't ever be propagated under any scheme, as we can't reason about indirect
-            // mutation.
-            | NonMutatingUse(NonMutatingUseContext::SharedBorrow)
-            | NonMutatingUse(NonMutatingUseContext::ShallowBorrow)
-            | NonMutatingUse(NonMutatingUseContext::UniqueBorrow)
-            | NonMutatingUse(NonMutatingUseContext::AddressOf)
-            | MutatingUse(MutatingUseContext::Borrow)
-            | MutatingUse(MutatingUseContext::AddressOf) => {
-                trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
-                self.can_const_prop[local] = ConstPropMode::NoPropagation;
-            }
-        }
-    }
-}
-
-impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_body(&mut self, body: &mut Body<'tcx>) {
-        for (bb, data) in body.basic_blocks_mut().iter_enumerated_mut() {
-            self.visit_basic_block_data(bb, data);
-        }
-    }
-
-    fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
-        self.super_operand(operand, location);
-
-        // Only const prop copies and moves on `mir_opt_level=3` as doing so
-        // currently slightly increases compile time in some cases.
-        if self.tcx.sess.mir_opt_level() >= 3 {
-            self.propagate_operand(operand)
-        }
-    }
-
-    fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
-        trace!("visit_constant: {:?}", constant);
-        self.super_constant(constant, location);
-        self.eval_constant(constant, self.source_info.unwrap());
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        trace!("visit_statement: {:?}", statement);
-        let source_info = statement.source_info;
-        self.source_info = Some(source_info);
-        if let StatementKind::Assign(box (place, ref mut rval)) = statement.kind {
-            let can_const_prop = self.ecx.machine.can_const_prop[place.local];
-            if let Some(()) = self.const_prop(rval, source_info, place) {
-                // This will return None if the above `const_prop` invocation only "wrote" a
-                // type whose creation requires no write. E.g. a generator whose initial state
-                // consists solely of uninitialized memory (so it doesn't capture any locals).
-                if let Some(ref value) = self.get_const(place) {
-                    if self.should_const_prop(value) {
-                        trace!("replacing {:?} with {:?}", rval, value);
-                        self.replace_with_const(rval, value, source_info);
-                        if can_const_prop == ConstPropMode::FullConstProp
-                            || can_const_prop == ConstPropMode::OnlyInsideOwnBlock
-                        {
-                            trace!("propagated into {:?}", place);
-                        }
-                    }
-                }
-                match can_const_prop {
-                    ConstPropMode::OnlyInsideOwnBlock => {
-                        trace!(
-                            "found local restricted to its block. \
-                                Will remove it from const-prop after block is finished. Local: {:?}",
-                            place.local
-                        );
-                    }
-                    ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
-                        trace!("can't propagate into {:?}", place);
-                        if place.local != RETURN_PLACE {
-                            Self::remove_const(&mut self.ecx, place.local);
-                        }
-                    }
-                    ConstPropMode::FullConstProp => {}
-                }
-            } else {
-                // Const prop failed, so erase the destination, ensuring that whatever happens
-                // from here on, does not know about the previous value.
-                // This is important in case we have
-                // ```rust
-                // let mut x = 42;
-                // x = SOME_MUTABLE_STATIC;
-                // // x must now be uninit
-                // ```
-                // FIXME: we overzealously erase the entire local, because that's easier to
-                // implement.
-                trace!(
-                    "propagation into {:?} failed.
-                        Nuking the entire site from orbit, it's the only way to be sure",
-                    place,
-                );
-                Self::remove_const(&mut self.ecx, place.local);
-            }
-        } else {
-            match statement.kind {
-                StatementKind::SetDiscriminant { ref place, .. } => {
-                    match self.ecx.machine.can_const_prop[place.local] {
-                        ConstPropMode::FullConstProp | ConstPropMode::OnlyInsideOwnBlock => {
-                            if self.use_ecx(|this| this.ecx.statement(statement)).is_some() {
-                                trace!("propped discriminant into {:?}", place);
-                            } else {
-                                Self::remove_const(&mut self.ecx, place.local);
-                            }
-                        }
-                        ConstPropMode::OnlyPropagateInto | ConstPropMode::NoPropagation => {
-                            Self::remove_const(&mut self.ecx, place.local);
-                        }
-                    }
-                }
-                StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
-                    let frame = self.ecx.frame_mut();
-                    frame.locals[local].value =
-                        if let StatementKind::StorageLive(_) = statement.kind {
-                            LocalValue::Uninitialized
-                        } else {
-                            LocalValue::Dead
-                        };
-                }
-                _ => {}
-            }
-        }
-
-        self.super_statement(statement, location);
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
-        let source_info = terminator.source_info;
-        self.source_info = Some(source_info);
-        self.super_terminator(terminator, location);
-        match &mut terminator.kind {
-            TerminatorKind::Assert { expected, ref msg, ref mut cond, .. } => {
-                if let Some(ref value) = self.eval_operand(&cond, source_info) {
-                    trace!("assertion on {:?} should be {:?}", value, expected);
-                    let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
-                    let value_const = self.ecx.read_scalar(&value).unwrap();
-                    if expected != value_const {
-                        enum DbgVal<T> {
-                            Val(T),
-                            Underscore,
-                        }
-                        impl<T: std::fmt::Debug> std::fmt::Debug for DbgVal<T> {
-                            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-                                match self {
-                                    Self::Val(val) => val.fmt(fmt),
-                                    Self::Underscore => fmt.write_str("_"),
-                                }
-                            }
-                        }
-                        let mut eval_to_int = |op| {
-                            // This can be `None` if the lhs wasn't const propagated and we just
-                            // triggered the assert on the value of the rhs.
-                            self.eval_operand(op, source_info).map_or(DbgVal::Underscore, |op| {
-                                DbgVal::Val(self.ecx.read_immediate(&op).unwrap().to_const_int())
-                            })
-                        };
-                        let msg = match msg {
-                            AssertKind::DivisionByZero(op) => {
-                                Some(AssertKind::DivisionByZero(eval_to_int(op)))
-                            }
-                            AssertKind::RemainderByZero(op) => {
-                                Some(AssertKind::RemainderByZero(eval_to_int(op)))
-                            }
-                            AssertKind::BoundsCheck { ref len, ref index } => {
-                                let len = eval_to_int(len);
-                                let index = eval_to_int(index);
-                                Some(AssertKind::BoundsCheck { len, index })
-                            }
-                            // Overflow is are already covered by checks on the binary operators.
-                            AssertKind::Overflow(..) | AssertKind::OverflowNeg(_) => None,
-                            // Need proper const propagator for these.
-                            _ => None,
-                        };
-                        // Poison all places this operand references so that further code
-                        // doesn't use the invalid value
-                        match cond {
-                            Operand::Move(ref place) | Operand::Copy(ref place) => {
-                                Self::remove_const(&mut self.ecx, place.local);
-                            }
-                            Operand::Constant(_) => {}
-                        }
-                        if let Some(msg) = msg {
-                            self.report_assert_as_lint(
-                                lint::builtin::UNCONDITIONAL_PANIC,
-                                source_info,
-                                "this operation will panic at runtime",
-                                msg,
-                            );
-                        }
-                    } else {
-                        if self.should_const_prop(value) {
-                            if let ScalarMaybeUninit::Scalar(scalar) = value_const {
-                                *cond = self.operand_from_scalar(
-                                    scalar,
-                                    self.tcx.types.bool,
-                                    source_info.span,
-                                );
-                            }
-                        }
-                    }
-                }
-            }
-            TerminatorKind::SwitchInt { ref mut discr, .. } => {
-                // FIXME: This is currently redundant with `visit_operand`, but sadly
-                // always visiting operands currently causes a perf regression in LLVM codegen, so
-                // `visit_operand` currently only runs for propagates places for `mir_opt_level=4`.
-                self.propagate_operand(discr)
-            }
-            // None of these have Operands to const-propagate.
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-            // Every argument in our function calls have already been propagated in `visit_operand`.
-            //
-            // NOTE: because LLVM codegen gives slight performance regressions with it, so this is
-            // gated on `mir_opt_level=3`.
-            TerminatorKind::Call { .. } => {}
-        }
-
-        // We remove all Locals which are restricted in propagation to their containing blocks and
-        // which were modified in the current block.
-        // Take it out of the ecx so we can get a mutable reference to the ecx for `remove_const`.
-        let mut locals = std::mem::take(&mut self.ecx.machine.written_only_inside_own_block_locals);
-        for &local in locals.iter() {
-            Self::remove_const(&mut self.ecx, local);
-        }
-        locals.clear();
-        // Put it back so we reuse the heap of the storage
-        self.ecx.machine.written_only_inside_own_block_locals = locals;
-        if cfg!(debug_assertions) {
-            // Ensure we are correctly erasing locals with the non-debug-assert logic.
-            for local in self.ecx.machine.only_propagate_inside_block_locals.iter() {
-                assert!(
-                    self.get_const(local.into()).is_none()
-                        || self
-                            .layout_of(self.local_decls[local].ty)
-                            .map_or(true, |layout| layout.is_zst())
-                )
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/counters.rs b/compiler/rustc_mir/src/transform/coverage/counters.rs
deleted file mode 100644
index 6726b669ff2..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/counters.rs
+++ /dev/null
@@ -1,614 +0,0 @@
-use super::Error;
-
-use super::debug;
-use super::graph;
-use super::spans;
-
-use debug::{DebugCounters, NESTED_INDENT};
-use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops};
-use spans::CoverageSpan;
-
-use rustc_data_structures::graph::WithNumNodes;
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::coverage::*;
-
-/// Manages the counter and expression indexes/IDs to generate `CoverageKind` components for MIR
-/// `Coverage` statements.
-pub(super) struct CoverageCounters {
-    function_source_hash: u64,
-    next_counter_id: u32,
-    num_expressions: u32,
-    pub debug_counters: DebugCounters,
-}
-
-impl CoverageCounters {
-    pub fn new(function_source_hash: u64) -> Self {
-        Self {
-            function_source_hash,
-            next_counter_id: CounterValueReference::START.as_u32(),
-            num_expressions: 0,
-            debug_counters: DebugCounters::new(),
-        }
-    }
-
-    /// Activate the `DebugCounters` data structures, to provide additional debug formatting
-    /// features when formatting `CoverageKind` (counter) values.
-    pub fn enable_debug(&mut self) {
-        self.debug_counters.enable();
-    }
-
-    /// Makes `CoverageKind` `Counter`s and `Expressions` for the `BasicCoverageBlock`s directly or
-    /// indirectly associated with `CoverageSpans`, and returns additional `Expression`s
-    /// representing intermediate values.
-    pub fn make_bcb_counters(
-        &mut self,
-        basic_coverage_blocks: &mut CoverageGraph,
-        coverage_spans: &Vec<CoverageSpan>,
-    ) -> Result<Vec<CoverageKind>, Error> {
-        let mut bcb_counters = BcbCounters::new(self, basic_coverage_blocks);
-        bcb_counters.make_bcb_counters(coverage_spans)
-    }
-
-    fn make_counter<F>(&mut self, debug_block_label_fn: F) -> CoverageKind
-    where
-        F: Fn() -> Option<String>,
-    {
-        let counter = CoverageKind::Counter {
-            function_source_hash: self.function_source_hash,
-            id: self.next_counter(),
-        };
-        if self.debug_counters.is_enabled() {
-            self.debug_counters.add_counter(&counter, (debug_block_label_fn)());
-        }
-        counter
-    }
-
-    fn make_expression<F>(
-        &mut self,
-        lhs: ExpressionOperandId,
-        op: Op,
-        rhs: ExpressionOperandId,
-        debug_block_label_fn: F,
-    ) -> CoverageKind
-    where
-        F: Fn() -> Option<String>,
-    {
-        let id = self.next_expression();
-        let expression = CoverageKind::Expression { id, lhs, op, rhs };
-        if self.debug_counters.is_enabled() {
-            self.debug_counters.add_counter(&expression, (debug_block_label_fn)());
-        }
-        expression
-    }
-
-    pub fn make_identity_counter(&mut self, counter_operand: ExpressionOperandId) -> CoverageKind {
-        let some_debug_block_label = if self.debug_counters.is_enabled() {
-            self.debug_counters.some_block_label(counter_operand).cloned()
-        } else {
-            None
-        };
-        self.make_expression(counter_operand, Op::Add, ExpressionOperandId::ZERO, || {
-            some_debug_block_label.clone()
-        })
-    }
-
-    /// Counter IDs start from one and go up.
-    fn next_counter(&mut self) -> CounterValueReference {
-        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
-        let next = self.next_counter_id;
-        self.next_counter_id += 1;
-        CounterValueReference::from(next)
-    }
-
-    /// Expression IDs start from u32::MAX and go down because an Expression can reference
-    /// (add or subtract counts) of both Counter regions and Expression regions. The counter
-    /// expression operand IDs must be unique across both types.
-    fn next_expression(&mut self) -> InjectedExpressionId {
-        assert!(self.next_counter_id < u32::MAX - self.num_expressions);
-        let next = u32::MAX - self.num_expressions;
-        self.num_expressions += 1;
-        InjectedExpressionId::from(next)
-    }
-}
-
-/// Traverse the `CoverageGraph` and add either a `Counter` or `Expression` to every BCB, to be
-/// injected with `CoverageSpan`s. `Expressions` have no runtime overhead, so if a viable expression
-/// (adding or subtracting two other counters or expressions) can compute the same result as an
-/// embedded counter, an `Expression` should be used.
-struct BcbCounters<'a> {
-    coverage_counters: &'a mut CoverageCounters,
-    basic_coverage_blocks: &'a mut CoverageGraph,
-}
-
-impl<'a> BcbCounters<'a> {
-    fn new(
-        coverage_counters: &'a mut CoverageCounters,
-        basic_coverage_blocks: &'a mut CoverageGraph,
-    ) -> Self {
-        Self { coverage_counters, basic_coverage_blocks }
-    }
-
-    /// If two `BasicCoverageBlock`s branch from another `BasicCoverageBlock`, one of the branches
-    /// can be counted by `Expression` by subtracting the other branch from the branching
-    /// block. Otherwise, the `BasicCoverageBlock` executed the least should have the `Counter`.
-    /// One way to predict which branch executes the least is by considering loops. A loop is exited
-    /// at a branch, so the branch that jumps to a `BasicCoverageBlock` outside the loop is almost
-    /// always executed less than the branch that does not exit the loop.
-    ///
-    /// Returns any non-code-span expressions created to represent intermediate values (such as to
-    /// add two counters so the result can be subtracted from another counter), or an Error with
-    /// message for subsequent debugging.
-    fn make_bcb_counters(
-        &mut self,
-        coverage_spans: &[CoverageSpan],
-    ) -> Result<Vec<CoverageKind>, Error> {
-        debug!("make_bcb_counters(): adding a counter or expression to each BasicCoverageBlock");
-        let num_bcbs = self.basic_coverage_blocks.num_nodes();
-        let mut collect_intermediate_expressions = Vec::with_capacity(num_bcbs);
-
-        let mut bcbs_with_coverage = BitSet::new_empty(num_bcbs);
-        for covspan in coverage_spans {
-            bcbs_with_coverage.insert(covspan.bcb);
-        }
-
-        // Walk the `CoverageGraph`. For each `BasicCoverageBlock` node with an associated
-        // `CoverageSpan`, add a counter. If the `BasicCoverageBlock` branches, add a counter or
-        // expression to each branch `BasicCoverageBlock` (if the branch BCB has only one incoming
-        // edge) or edge from the branching BCB to the branch BCB (if the branch BCB has multiple
-        // incoming edges).
-        //
-        // The `TraverseCoverageGraphWithLoops` traversal ensures that, when a loop is encountered,
-        // all `BasicCoverageBlock` nodes in the loop are visited before visiting any node outside
-        // the loop. The `traversal` state includes a `context_stack`, providing a way to know if
-        // the current BCB is in one or more nested loops or not.
-        let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks);
-        while let Some(bcb) = traversal.next(self.basic_coverage_blocks) {
-            if bcbs_with_coverage.contains(bcb) {
-                debug!("{:?} has at least one `CoverageSpan`. Get or make its counter", bcb);
-                let branching_counter_operand =
-                    self.get_or_make_counter_operand(bcb, &mut collect_intermediate_expressions)?;
-
-                if self.bcb_needs_branch_counters(bcb) {
-                    self.make_branch_counters(
-                        &mut traversal,
-                        bcb,
-                        branching_counter_operand,
-                        &mut collect_intermediate_expressions,
-                    )?;
-                }
-            } else {
-                debug!(
-                    "{:?} does not have any `CoverageSpan`s. A counter will only be added if \
-                    and when a covered BCB has an expression dependency.",
-                    bcb,
-                );
-            }
-        }
-
-        if traversal.is_complete() {
-            Ok(collect_intermediate_expressions)
-        } else {
-            Error::from_string(format!(
-                "`TraverseCoverageGraphWithLoops` missed some `BasicCoverageBlock`s: {:?}",
-                traversal.unvisited(),
-            ))
-        }
-    }
-
-    fn make_branch_counters(
-        &mut self,
-        traversal: &mut TraverseCoverageGraphWithLoops,
-        branching_bcb: BasicCoverageBlock,
-        branching_counter_operand: ExpressionOperandId,
-        collect_intermediate_expressions: &mut Vec<CoverageKind>,
-    ) -> Result<(), Error> {
-        let branches = self.bcb_branches(branching_bcb);
-        debug!(
-            "{:?} has some branch(es) without counters:\n  {}",
-            branching_bcb,
-            branches
-                .iter()
-                .map(|branch| {
-                    format!("{:?}: {:?}", branch, branch.counter(&self.basic_coverage_blocks))
-                })
-                .collect::<Vec<_>>()
-                .join("\n  "),
-        );
-
-        // Use the `traversal` state to decide if a subset of the branches exit a loop, making it
-        // likely that branch is executed less than branches that do not exit the same loop. In this
-        // case, any branch that does not exit the loop (and has not already been assigned a
-        // counter) should be counted by expression, if possible. (If a preferred expression branch
-        // is not selected based on the loop context, select any branch without an existing
-        // counter.)
-        let expression_branch = self.choose_preferred_expression_branch(traversal, &branches);
-
-        // Assign a Counter or Expression to each branch, plus additional `Expression`s, as needed,
-        // to sum up intermediate results.
-        let mut some_sumup_counter_operand = None;
-        for branch in branches {
-            // Skip the selected `expression_branch`, if any. It's expression will be assigned after
-            // all others.
-            if branch != expression_branch {
-                let branch_counter_operand = if branch.is_only_path_to_target() {
-                    debug!(
-                        "  {:?} has only one incoming edge (from {:?}), so adding a \
-                        counter",
-                        branch, branching_bcb
-                    );
-                    self.get_or_make_counter_operand(
-                        branch.target_bcb,
-                        collect_intermediate_expressions,
-                    )?
-                } else {
-                    debug!("  {:?} has multiple incoming edges, so adding an edge counter", branch);
-                    self.get_or_make_edge_counter_operand(
-                        branching_bcb,
-                        branch.target_bcb,
-                        collect_intermediate_expressions,
-                    )?
-                };
-                if let Some(sumup_counter_operand) =
-                    some_sumup_counter_operand.replace(branch_counter_operand)
-                {
-                    let intermediate_expression = self.coverage_counters.make_expression(
-                        branch_counter_operand,
-                        Op::Add,
-                        sumup_counter_operand,
-                        || None,
-                    );
-                    debug!(
-                        "  [new intermediate expression: {}]",
-                        self.format_counter(&intermediate_expression)
-                    );
-                    let intermediate_expression_operand = intermediate_expression.as_operand_id();
-                    collect_intermediate_expressions.push(intermediate_expression);
-                    some_sumup_counter_operand.replace(intermediate_expression_operand);
-                }
-            }
-        }
-
-        // Assign the final expression to the `expression_branch` by subtracting the total of all
-        // other branches from the counter of the branching BCB.
-        let sumup_counter_operand =
-            some_sumup_counter_operand.expect("sumup_counter_operand should have a value");
-        debug!(
-            "Making an expression for the selected expression_branch: {:?} \
-            (expression_branch predecessors: {:?})",
-            expression_branch,
-            self.bcb_predecessors(expression_branch.target_bcb),
-        );
-        let expression = self.coverage_counters.make_expression(
-            branching_counter_operand,
-            Op::Subtract,
-            sumup_counter_operand,
-            || Some(format!("{:?}", expression_branch)),
-        );
-        debug!("{:?} gets an expression: {}", expression_branch, self.format_counter(&expression));
-        let bcb = expression_branch.target_bcb;
-        if expression_branch.is_only_path_to_target() {
-            self.basic_coverage_blocks[bcb].set_counter(expression)?;
-        } else {
-            self.basic_coverage_blocks[bcb].set_edge_counter_from(branching_bcb, expression)?;
-        }
-        Ok(())
-    }
-
-    fn get_or_make_counter_operand(
-        &mut self,
-        bcb: BasicCoverageBlock,
-        collect_intermediate_expressions: &mut Vec<CoverageKind>,
-    ) -> Result<ExpressionOperandId, Error> {
-        self.recursive_get_or_make_counter_operand(bcb, collect_intermediate_expressions, 1)
-    }
-
-    fn recursive_get_or_make_counter_operand(
-        &mut self,
-        bcb: BasicCoverageBlock,
-        collect_intermediate_expressions: &mut Vec<CoverageKind>,
-        debug_indent_level: usize,
-    ) -> Result<ExpressionOperandId, Error> {
-        // If the BCB already has a counter, return it.
-        if let Some(counter_kind) = self.basic_coverage_blocks[bcb].counter() {
-            debug!(
-                "{}{:?} already has a counter: {}",
-                NESTED_INDENT.repeat(debug_indent_level),
-                bcb,
-                self.format_counter(counter_kind),
-            );
-            return Ok(counter_kind.as_operand_id());
-        }
-
-        // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`).
-        // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the
-        // program results in a tight infinite loop, but it should still compile.
-        let one_path_to_target = self.bcb_has_one_path_to_target(bcb);
-        if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) {
-            let counter_kind = self.coverage_counters.make_counter(|| Some(format!("{:?}", bcb)));
-            if one_path_to_target {
-                debug!(
-                    "{}{:?} gets a new counter: {}",
-                    NESTED_INDENT.repeat(debug_indent_level),
-                    bcb,
-                    self.format_counter(&counter_kind),
-                );
-            } else {
-                debug!(
-                    "{}{:?} has itself as its own predecessor. It can't be part of its own \
-                    Expression sum, so it will get its own new counter: {}. (Note, the compiled \
-                    code will generate an infinite loop.)",
-                    NESTED_INDENT.repeat(debug_indent_level),
-                    bcb,
-                    self.format_counter(&counter_kind),
-                );
-            }
-            return self.basic_coverage_blocks[bcb].set_counter(counter_kind);
-        }
-
-        // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the
-        // counters and/or expressions of its incoming edges. This will recursively get or create
-        // counters for those incoming edges first, then call `make_expression()` to sum them up,
-        // with additional intermediate expressions as needed.
-        let mut predecessors = self.bcb_predecessors(bcb).clone().into_iter();
-        debug!(
-            "{}{:?} has multiple incoming edges and will get an expression that sums them up...",
-            NESTED_INDENT.repeat(debug_indent_level),
-            bcb,
-        );
-        let first_edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
-            predecessors.next().unwrap(),
-            bcb,
-            collect_intermediate_expressions,
-            debug_indent_level + 1,
-        )?;
-        let mut some_sumup_edge_counter_operand = None;
-        for predecessor in predecessors {
-            let edge_counter_operand = self.recursive_get_or_make_edge_counter_operand(
-                predecessor,
-                bcb,
-                collect_intermediate_expressions,
-                debug_indent_level + 1,
-            )?;
-            if let Some(sumup_edge_counter_operand) =
-                some_sumup_edge_counter_operand.replace(edge_counter_operand)
-            {
-                let intermediate_expression = self.coverage_counters.make_expression(
-                    sumup_edge_counter_operand,
-                    Op::Add,
-                    edge_counter_operand,
-                    || None,
-                );
-                debug!(
-                    "{}new intermediate expression: {}",
-                    NESTED_INDENT.repeat(debug_indent_level),
-                    self.format_counter(&intermediate_expression)
-                );
-                let intermediate_expression_operand = intermediate_expression.as_operand_id();
-                collect_intermediate_expressions.push(intermediate_expression);
-                some_sumup_edge_counter_operand.replace(intermediate_expression_operand);
-            }
-        }
-        let counter_kind = self.coverage_counters.make_expression(
-            first_edge_counter_operand,
-            Op::Add,
-            some_sumup_edge_counter_operand.unwrap(),
-            || Some(format!("{:?}", bcb)),
-        );
-        debug!(
-            "{}{:?} gets a new counter (sum of predecessor counters): {}",
-            NESTED_INDENT.repeat(debug_indent_level),
-            bcb,
-            self.format_counter(&counter_kind)
-        );
-        self.basic_coverage_blocks[bcb].set_counter(counter_kind)
-    }
-
-    fn get_or_make_edge_counter_operand(
-        &mut self,
-        from_bcb: BasicCoverageBlock,
-        to_bcb: BasicCoverageBlock,
-        collect_intermediate_expressions: &mut Vec<CoverageKind>,
-    ) -> Result<ExpressionOperandId, Error> {
-        self.recursive_get_or_make_edge_counter_operand(
-            from_bcb,
-            to_bcb,
-            collect_intermediate_expressions,
-            1,
-        )
-    }
-
-    fn recursive_get_or_make_edge_counter_operand(
-        &mut self,
-        from_bcb: BasicCoverageBlock,
-        to_bcb: BasicCoverageBlock,
-        collect_intermediate_expressions: &mut Vec<CoverageKind>,
-        debug_indent_level: usize,
-    ) -> Result<ExpressionOperandId, Error> {
-        // If the source BCB has only one successor (assumed to be the given target), an edge
-        // counter is unnecessary. Just get or make a counter for the source BCB.
-        let successors = self.bcb_successors(from_bcb).iter();
-        if successors.len() == 1 {
-            return self.recursive_get_or_make_counter_operand(
-                from_bcb,
-                collect_intermediate_expressions,
-                debug_indent_level + 1,
-            );
-        }
-
-        // If the edge already has a counter, return it.
-        if let Some(counter_kind) = self.basic_coverage_blocks[to_bcb].edge_counter_from(from_bcb) {
-            debug!(
-                "{}Edge {:?}->{:?} already has a counter: {}",
-                NESTED_INDENT.repeat(debug_indent_level),
-                from_bcb,
-                to_bcb,
-                self.format_counter(counter_kind)
-            );
-            return Ok(counter_kind.as_operand_id());
-        }
-
-        // Make a new counter to count this edge.
-        let counter_kind =
-            self.coverage_counters.make_counter(|| Some(format!("{:?}->{:?}", from_bcb, to_bcb)));
-        debug!(
-            "{}Edge {:?}->{:?} gets a new counter: {}",
-            NESTED_INDENT.repeat(debug_indent_level),
-            from_bcb,
-            to_bcb,
-            self.format_counter(&counter_kind)
-        );
-        self.basic_coverage_blocks[to_bcb].set_edge_counter_from(from_bcb, counter_kind)
-    }
-
-    /// Select a branch for the expression, either the recommended `reloop_branch`, or if none was
-    /// found, select any branch.
-    fn choose_preferred_expression_branch(
-        &self,
-        traversal: &TraverseCoverageGraphWithLoops,
-        branches: &[BcbBranch],
-    ) -> BcbBranch {
-        let branch_needs_a_counter =
-            |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
-
-        let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches);
-        if let Some(reloop_branch_without_counter) =
-            some_reloop_branch.filter(branch_needs_a_counter)
-        {
-            debug!(
-                "Selecting reloop_branch={:?} that still needs a counter, to get the \
-                `Expression`",
-                reloop_branch_without_counter
-            );
-            reloop_branch_without_counter
-        } else {
-            let &branch_without_counter = branches
-                .iter()
-                .find(|&&branch| branch.counter(&self.basic_coverage_blocks).is_none())
-                .expect(
-                    "needs_branch_counters was `true` so there should be at least one \
-                    branch",
-                );
-            debug!(
-                "Selecting any branch={:?} that still needs a counter, to get the \
-                `Expression` because there was no `reloop_branch`, or it already had a \
-                counter",
-                branch_without_counter
-            );
-            branch_without_counter
-        }
-    }
-
-    /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has
-    /// multiple incoming edges) can have a counter computed by expression.
-    ///
-    /// If at least one of the branches leads outside of a loop (`found_loop_exit` is
-    /// true), and at least one other branch does not exit the loop (the first of which
-    /// is captured in `some_reloop_branch`), it's likely any reloop branch will be
-    /// executed far more often than loop exit branch, making the reloop branch a better
-    /// candidate for an expression.
-    fn find_some_reloop_branch(
-        &self,
-        traversal: &TraverseCoverageGraphWithLoops,
-        branches: &[BcbBranch],
-    ) -> Option<BcbBranch> {
-        let branch_needs_a_counter =
-            |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
-
-        let mut some_reloop_branch: Option<BcbBranch> = None;
-        for context in traversal.context_stack.iter().rev() {
-            if let Some((backedge_from_bcbs, _)) = &context.loop_backedges {
-                let mut found_loop_exit = false;
-                for &branch in branches.iter() {
-                    if backedge_from_bcbs.iter().any(|&backedge_from_bcb| {
-                        self.bcb_is_dominated_by(backedge_from_bcb, branch.target_bcb)
-                    }) {
-                        if let Some(reloop_branch) = some_reloop_branch {
-                            if reloop_branch.counter(&self.basic_coverage_blocks).is_none() {
-                                // we already found a candidate reloop_branch that still
-                                // needs a counter
-                                continue;
-                            }
-                        }
-                        // The path from branch leads back to the top of the loop. Set this
-                        // branch as the `reloop_branch`. If this branch already has a
-                        // counter, and we find another reloop branch that doesn't have a
-                        // counter yet, that branch will be selected as the `reloop_branch`
-                        // instead.
-                        some_reloop_branch = Some(branch);
-                    } else {
-                        // The path from branch leads outside this loop
-                        found_loop_exit = true;
-                    }
-                    if found_loop_exit
-                        && some_reloop_branch.filter(branch_needs_a_counter).is_some()
-                    {
-                        // Found both a branch that exits the loop and a branch that returns
-                        // to the top of the loop (`reloop_branch`), and the `reloop_branch`
-                        // doesn't already have a counter.
-                        break;
-                    }
-                }
-                if !found_loop_exit {
-                    debug!(
-                        "No branches exit the loop, so any branch without an existing \
-                        counter can have the `Expression`."
-                    );
-                    break;
-                }
-                if some_reloop_branch.is_some() {
-                    debug!(
-                        "Found a branch that exits the loop and a branch the loops back to \
-                        the top of the loop (`reloop_branch`). The `reloop_branch` will \
-                        get the `Expression`, as long as it still needs a counter."
-                    );
-                    break;
-                }
-                // else all branches exited this loop context, so run the same checks with
-                // the outer loop(s)
-            }
-        }
-        some_reloop_branch
-    }
-
-    #[inline]
-    fn bcb_predecessors(&self, bcb: BasicCoverageBlock) -> &Vec<BasicCoverageBlock> {
-        &self.basic_coverage_blocks.predecessors[bcb]
-    }
-
-    #[inline]
-    fn bcb_successors(&self, bcb: BasicCoverageBlock) -> &Vec<BasicCoverageBlock> {
-        &self.basic_coverage_blocks.successors[bcb]
-    }
-
-    #[inline]
-    fn bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec<BcbBranch> {
-        self.bcb_successors(from_bcb)
-            .iter()
-            .map(|&to_bcb| BcbBranch::from_to(from_bcb, to_bcb, &self.basic_coverage_blocks))
-            .collect::<Vec<_>>()
-    }
-
-    fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool {
-        let branch_needs_a_counter =
-            |branch: &BcbBranch| branch.counter(&self.basic_coverage_blocks).is_none();
-        let branches = self.bcb_branches(bcb);
-        branches.len() > 1 && branches.iter().any(branch_needs_a_counter)
-    }
-
-    /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be
-    /// the entry point for the function.)
-    #[inline]
-    fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool {
-        self.bcb_predecessors(bcb).len() <= 1
-    }
-
-    #[inline]
-    fn bcb_is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool {
-        self.basic_coverage_blocks.is_dominated_by(node, dom)
-    }
-
-    #[inline]
-    fn format_counter(&self, counter_kind: &CoverageKind) -> String {
-        self.coverage_counters.debug_counters.format_counter(counter_kind)
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs
deleted file mode 100644
index 464079656f9..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/debug.rs
+++ /dev/null
@@ -1,840 +0,0 @@
-//! The `InstrumentCoverage` MIR pass implementation includes debugging tools and options
-//! to help developers understand and/or improve the analysis and instrumentation of a MIR.
-//!
-//! To enable coverage, include the rustc command line option:
-//!
-//!   * `-Z instrument-coverage`
-//!
-//! MIR Dump Files, with additional `CoverageGraph` graphviz and `CoverageSpan` spanview
-//! ------------------------------------------------------------------------------------
-//!
-//! Additional debugging options include:
-//!
-//!   * `-Z dump-mir=InstrumentCoverage` - Generate `.mir` files showing the state of the MIR,
-//!     before and after the `InstrumentCoverage` pass, for each compiled function.
-//!
-//!   * `-Z dump-mir-graphviz` - If `-Z dump-mir` is also enabled for the current MIR node path,
-//!     each MIR dump is accompanied by a before-and-after graphical view of the MIR, in Graphviz
-//!     `.dot` file format (which can be visually rendered as a graph using any of a number of free
-//!     Graphviz viewers and IDE extensions).
-//!
-//!     For the `InstrumentCoverage` pass, this option also enables generation of an additional
-//!     Graphviz `.dot` file for each function, rendering the `CoverageGraph`: the control flow
-//!     graph (CFG) of `BasicCoverageBlocks` (BCBs), as nodes, internally labeled to show the
-//!     `CoverageSpan`-based MIR elements each BCB represents (`BasicBlock`s, `Statement`s and
-//!     `Terminator`s), assigned coverage counters and/or expressions, and edge counters, as needed.
-//!
-//!     (Note the additional option, `-Z graphviz-dark-mode`, can be added, to change the rendered
-//!     output from its default black-on-white background to a dark color theme, if desired.)
-//!
-//!   * `-Z dump-mir-spanview` - If `-Z dump-mir` is also enabled for the current MIR node path,
-//!     each MIR dump is accompanied by a before-and-after `.html` document showing the function's
-//!     original source code, highlighted by it's MIR spans, at the `statement`-level (by default),
-//!     `terminator` only, or encompassing span for the `Terminator` plus all `Statement`s, in each
-//!     `block` (`BasicBlock`).
-//!
-//!     For the `InstrumentCoverage` pass, this option also enables generation of an additional
-//!     spanview `.html` file for each function, showing the aggregated `CoverageSpan`s that will
-//!     require counters (or counter expressions) for accurate coverage analysis.
-//!
-//! Debug Logging
-//! -------------
-//!
-//! The `InstrumentCoverage` pass includes debug logging messages at various phases and decision
-//! points, which can be enabled via environment variable:
-//!
-//! ```shell
-//! RUSTC_LOG=rustc_mir::transform::coverage=debug
-//! ```
-//!
-//! Other module paths with coverage-related debug logs may also be of interest, particularly for
-//! debugging the coverage map data, injected as global variables in the LLVM IR (during rustc's
-//! code generation pass). For example:
-//!
-//! ```shell
-//! RUSTC_LOG=rustc_mir::transform::coverage,rustc_codegen_ssa::coverageinfo,rustc_codegen_llvm::coverageinfo=debug
-//! ```
-//!
-//! Coverage Debug Options
-//! ---------------------------------
-//!
-//! Additional debugging options can be enabled using the environment variable:
-//!
-//! ```shell
-//! RUSTC_COVERAGE_DEBUG_OPTIONS=<options>
-//! ```
-//!
-//! These options are comma-separated, and specified in the format `option-name=value`. For example:
-//!
-//! ```shell
-//! $ RUSTC_COVERAGE_DEBUG_OPTIONS=counter-format=id+operation,allow-unused-expressions=yes cargo build
-//! ```
-//!
-//! Coverage debug options include:
-//!
-//!   * `allow-unused-expressions=yes` or `no` (default: `no`)
-//!
-//!     The `InstrumentCoverage` algorithms _should_ only create and assign expressions to a
-//!     `BasicCoverageBlock`, or an incoming edge, if that expression is either (a) required to
-//!     count a `CoverageSpan`, or (b) a dependency of some other required counter expression.
-//!
-//!     If an expression is generated that does not map to a `CoverageSpan` or dependency, this
-//!     probably indicates there was a bug in the algorithm that creates and assigns counters
-//!     and expressions.
-//!
-//!     When this kind of bug is encountered, the rustc compiler will panic by default. Setting:
-//!     `allow-unused-expressions=yes` will log a warning message instead of panicking (effectively
-//!     ignoring the unused expressions), which may be helpful when debugging the root cause of
-//!     the problem.
-//!
-//!   * `counter-format=<choices>`, where `<choices>` can be any plus-separated combination of `id`,
-//!     `block`, and/or `operation` (default: `block+operation`)
-//!
-//!     This option effects both the `CoverageGraph` (graphviz `.dot` files) and debug logging, when
-//!     generating labels for counters and expressions.
-//!
-//!     Depending on the values and combinations, counters can be labeled by:
-//!
-//!       * `id` - counter or expression ID (ascending counter IDs, starting at 1, or descending
-//!         expression IDs, starting at `u32:MAX`)
-//!       * `block` - the `BasicCoverageBlock` label (for example, `bcb0`) or edge label (for
-//!         example `bcb0->bcb1`), for counters or expressions assigned to count a
-//!         `BasicCoverageBlock` or edge. Intermediate expressions (not directly associated with
-//!         a BCB or edge) will be labeled by their expression ID, unless `operation` is also
-//!         specified.
-//!       * `operation` - applied to expressions only, labels include the left-hand-side counter
-//!         or expression label (lhs operand), the operator (`+` or `-`), and the right-hand-side
-//!         counter or expression (rhs operand). Expression operand labels are generated
-//!         recursively, generating labels with nested operations, enclosed in parentheses
-//!         (for example: `bcb2 + (bcb0 - bcb1)`).
-
-use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
-use super::spans::CoverageSpan;
-
-use crate::util::generic_graphviz::GraphvizWriter;
-use crate::util::pretty;
-use crate::util::spanview::{self, SpanViewable};
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
-use rustc_middle::ty::TyCtxt;
-use rustc_span::Span;
-
-use std::iter;
-use std::lazy::SyncOnceCell;
-
-pub const NESTED_INDENT: &str = "    ";
-
-const RUSTC_COVERAGE_DEBUG_OPTIONS: &str = "RUSTC_COVERAGE_DEBUG_OPTIONS";
-
-pub(super) fn debug_options<'a>() -> &'a DebugOptions {
-    static DEBUG_OPTIONS: SyncOnceCell<DebugOptions> = SyncOnceCell::new();
-
-    &DEBUG_OPTIONS.get_or_init(DebugOptions::from_env)
-}
-
-/// Parses and maintains coverage-specific debug options captured from the environment variable
-/// "RUSTC_COVERAGE_DEBUG_OPTIONS", if set.
-#[derive(Debug, Clone)]
-pub(super) struct DebugOptions {
-    pub allow_unused_expressions: bool,
-    counter_format: ExpressionFormat,
-}
-
-impl DebugOptions {
-    fn from_env() -> Self {
-        let mut allow_unused_expressions = true;
-        let mut counter_format = ExpressionFormat::default();
-
-        if let Ok(env_debug_options) = std::env::var(RUSTC_COVERAGE_DEBUG_OPTIONS) {
-            for setting_str in env_debug_options.replace(" ", "").replace("-", "_").split(',') {
-                let (option, value) = match setting_str.split_once('=') {
-                    None => (setting_str, None),
-                    Some((k, v)) => (k, Some(v)),
-                };
-                match option {
-                    "allow_unused_expressions" => {
-                        allow_unused_expressions = bool_option_val(option, value);
-                        debug!(
-                            "{} env option `allow_unused_expressions` is set to {}",
-                            RUSTC_COVERAGE_DEBUG_OPTIONS, allow_unused_expressions
-                        );
-                    }
-                    "counter_format" => {
-                        match value {
-                            None => {
-                                bug!(
-                                    "`{}` option in environment variable {} requires one or more \
-                                    plus-separated choices (a non-empty subset of \
-                                    `id+block+operation`)",
-                                    option,
-                                    RUSTC_COVERAGE_DEBUG_OPTIONS
-                                );
-                            }
-                            Some(val) => {
-                                counter_format = counter_format_option_val(val);
-                                debug!(
-                                    "{} env option `counter_format` is set to {:?}",
-                                    RUSTC_COVERAGE_DEBUG_OPTIONS, counter_format
-                                );
-                            }
-                        };
-                    }
-                    _ => {
-                        bug!(
-                            "Unsupported setting `{}` in environment variable {}",
-                            option,
-                            RUSTC_COVERAGE_DEBUG_OPTIONS
-                        )
-                    }
-                };
-            }
-        }
-
-        Self { allow_unused_expressions, counter_format }
-    }
-}
-
-fn bool_option_val(option: &str, some_strval: Option<&str>) -> bool {
-    if let Some(val) = some_strval {
-        if vec!["yes", "y", "on", "true"].contains(&val) {
-            true
-        } else if vec!["no", "n", "off", "false"].contains(&val) {
-            false
-        } else {
-            bug!(
-                "Unsupported value `{}` for option `{}` in environment variable {}",
-                option,
-                val,
-                RUSTC_COVERAGE_DEBUG_OPTIONS
-            )
-        }
-    } else {
-        true
-    }
-}
-
-fn counter_format_option_val(strval: &str) -> ExpressionFormat {
-    let mut counter_format = ExpressionFormat { id: false, block: false, operation: false };
-    let components = strval.splitn(3, '+');
-    for component in components {
-        match component {
-            "id" => counter_format.id = true,
-            "block" => counter_format.block = true,
-            "operation" => counter_format.operation = true,
-            _ => bug!(
-                "Unsupported counter_format choice `{}` in environment variable {}",
-                component,
-                RUSTC_COVERAGE_DEBUG_OPTIONS
-            ),
-        }
-    }
-    counter_format
-}
-
-#[derive(Debug, Clone)]
-struct ExpressionFormat {
-    id: bool,
-    block: bool,
-    operation: bool,
-}
-
-impl Default for ExpressionFormat {
-    fn default() -> Self {
-        Self { id: false, block: true, operation: true }
-    }
-}
-
-/// If enabled, this struct maintains a map from `CoverageKind` IDs (as `ExpressionOperandId`) to
-/// the `CoverageKind` data and optional label (normally, the counter's associated
-/// `BasicCoverageBlock` format string, if any).
-///
-/// Use `format_counter` to convert one of these `CoverageKind` counters to a debug output string,
-/// as directed by the `DebugOptions`. This allows the format of counter labels in logs and dump
-/// files (including the `CoverageGraph` graphviz file) to be changed at runtime, via environment
-/// variable.
-///
-/// `DebugCounters` supports a recursive rendering of `Expression` counters, so they can be
-/// presented as nested expressions such as `(bcb3 - (bcb0 + bcb1))`.
-pub(super) struct DebugCounters {
-    some_counters: Option<FxHashMap<ExpressionOperandId, DebugCounter>>,
-}
-
-impl DebugCounters {
-    pub fn new() -> Self {
-        Self { some_counters: None }
-    }
-
-    pub fn enable(&mut self) {
-        debug_assert!(!self.is_enabled());
-        self.some_counters.replace(FxHashMap::default());
-    }
-
-    pub fn is_enabled(&self) -> bool {
-        self.some_counters.is_some()
-    }
-
-    pub fn add_counter(&mut self, counter_kind: &CoverageKind, some_block_label: Option<String>) {
-        if let Some(counters) = &mut self.some_counters {
-            let id: ExpressionOperandId = match *counter_kind {
-                CoverageKind::Counter { id, .. } => id.into(),
-                CoverageKind::Expression { id, .. } => id.into(),
-                _ => bug!(
-                    "the given `CoverageKind` is not an counter or expression: {:?}",
-                    counter_kind
-                ),
-            };
-            counters
-                .try_insert(id, DebugCounter::new(counter_kind.clone(), some_block_label))
-                .expect("attempt to add the same counter_kind to DebugCounters more than once");
-        }
-    }
-
-    pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> {
-        self.some_counters.as_ref().map_or(None, |counters| {
-            counters
-                .get(&operand)
-                .map_or(None, |debug_counter| debug_counter.some_block_label.as_ref())
-        })
-    }
-
-    pub fn format_counter(&self, counter_kind: &CoverageKind) -> String {
-        match *counter_kind {
-            CoverageKind::Counter { .. } => {
-                format!("Counter({})", self.format_counter_kind(counter_kind))
-            }
-            CoverageKind::Expression { .. } => {
-                format!("Expression({})", self.format_counter_kind(counter_kind))
-            }
-            CoverageKind::Unreachable { .. } => "Unreachable".to_owned(),
-        }
-    }
-
-    fn format_counter_kind(&self, counter_kind: &CoverageKind) -> String {
-        let counter_format = &debug_options().counter_format;
-        if let CoverageKind::Expression { id, lhs, op, rhs } = *counter_kind {
-            if counter_format.operation {
-                return format!(
-                    "{}{} {} {}",
-                    if counter_format.id || self.some_counters.is_none() {
-                        format!("#{} = ", id.index())
-                    } else {
-                        String::new()
-                    },
-                    self.format_operand(lhs),
-                    if op == Op::Add { "+" } else { "-" },
-                    self.format_operand(rhs),
-                );
-            }
-        }
-
-        let id: ExpressionOperandId = match *counter_kind {
-            CoverageKind::Counter { id, .. } => id.into(),
-            CoverageKind::Expression { id, .. } => id.into(),
-            _ => {
-                bug!("the given `CoverageKind` is not an counter or expression: {:?}", counter_kind)
-            }
-        };
-        if self.some_counters.is_some() && (counter_format.block || !counter_format.id) {
-            let counters = self.some_counters.as_ref().unwrap();
-            if let Some(DebugCounter { some_block_label: Some(block_label), .. }) =
-                counters.get(&id)
-            {
-                return if counter_format.id {
-                    format!("{}#{}", block_label, id.index())
-                } else {
-                    block_label.to_string()
-                };
-            }
-        }
-        format!("#{}", id.index())
-    }
-
-    fn format_operand(&self, operand: ExpressionOperandId) -> String {
-        if operand.index() == 0 {
-            return String::from("0");
-        }
-        if let Some(counters) = &self.some_counters {
-            if let Some(DebugCounter { counter_kind, some_block_label }) = counters.get(&operand) {
-                if let CoverageKind::Expression { .. } = counter_kind {
-                    if let Some(block_label) = some_block_label {
-                        if debug_options().counter_format.block {
-                            return format!(
-                                "{}:({})",
-                                block_label,
-                                self.format_counter_kind(counter_kind)
-                            );
-                        }
-                    }
-                    return format!("({})", self.format_counter_kind(counter_kind));
-                }
-                return self.format_counter_kind(counter_kind);
-            }
-        }
-        format!("#{}", operand.index())
-    }
-}
-
-/// A non-public support class to `DebugCounters`.
-#[derive(Debug)]
-struct DebugCounter {
-    counter_kind: CoverageKind,
-    some_block_label: Option<String>,
-}
-
-impl DebugCounter {
-    fn new(counter_kind: CoverageKind, some_block_label: Option<String>) -> Self {
-        Self { counter_kind, some_block_label }
-    }
-}
-
-/// If enabled, this data structure captures additional debugging information used when generating
-/// a Graphviz (.dot file) representation of the `CoverageGraph`, for debugging purposes.
-pub(super) struct GraphvizData {
-    some_bcb_to_coverage_spans_with_counters:
-        Option<FxHashMap<BasicCoverageBlock, Vec<(CoverageSpan, CoverageKind)>>>,
-    some_bcb_to_dependency_counters: Option<FxHashMap<BasicCoverageBlock, Vec<CoverageKind>>>,
-    some_edge_to_counter: Option<FxHashMap<(BasicCoverageBlock, BasicBlock), CoverageKind>>,
-}
-
-impl GraphvizData {
-    pub fn new() -> Self {
-        Self {
-            some_bcb_to_coverage_spans_with_counters: None,
-            some_bcb_to_dependency_counters: None,
-            some_edge_to_counter: None,
-        }
-    }
-
-    pub fn enable(&mut self) {
-        debug_assert!(!self.is_enabled());
-        self.some_bcb_to_coverage_spans_with_counters = Some(FxHashMap::default());
-        self.some_bcb_to_dependency_counters = Some(FxHashMap::default());
-        self.some_edge_to_counter = Some(FxHashMap::default());
-    }
-
-    pub fn is_enabled(&self) -> bool {
-        self.some_bcb_to_coverage_spans_with_counters.is_some()
-    }
-
-    pub fn add_bcb_coverage_span_with_counter(
-        &mut self,
-        bcb: BasicCoverageBlock,
-        coverage_span: &CoverageSpan,
-        counter_kind: &CoverageKind,
-    ) {
-        if let Some(bcb_to_coverage_spans_with_counters) =
-            self.some_bcb_to_coverage_spans_with_counters.as_mut()
-        {
-            bcb_to_coverage_spans_with_counters
-                .entry(bcb)
-                .or_insert_with(Vec::new)
-                .push((coverage_span.clone(), counter_kind.clone()));
-        }
-    }
-
-    pub fn get_bcb_coverage_spans_with_counters(
-        &self,
-        bcb: BasicCoverageBlock,
-    ) -> Option<&Vec<(CoverageSpan, CoverageKind)>> {
-        if let Some(bcb_to_coverage_spans_with_counters) =
-            self.some_bcb_to_coverage_spans_with_counters.as_ref()
-        {
-            bcb_to_coverage_spans_with_counters.get(&bcb)
-        } else {
-            None
-        }
-    }
-
-    pub fn add_bcb_dependency_counter(
-        &mut self,
-        bcb: BasicCoverageBlock,
-        counter_kind: &CoverageKind,
-    ) {
-        if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_mut() {
-            bcb_to_dependency_counters
-                .entry(bcb)
-                .or_insert_with(Vec::new)
-                .push(counter_kind.clone());
-        }
-    }
-
-    pub fn get_bcb_dependency_counters(
-        &self,
-        bcb: BasicCoverageBlock,
-    ) -> Option<&Vec<CoverageKind>> {
-        if let Some(bcb_to_dependency_counters) = self.some_bcb_to_dependency_counters.as_ref() {
-            bcb_to_dependency_counters.get(&bcb)
-        } else {
-            None
-        }
-    }
-
-    pub fn set_edge_counter(
-        &mut self,
-        from_bcb: BasicCoverageBlock,
-        to_bb: BasicBlock,
-        counter_kind: &CoverageKind,
-    ) {
-        if let Some(edge_to_counter) = self.some_edge_to_counter.as_mut() {
-            edge_to_counter
-                .try_insert((from_bcb, to_bb), counter_kind.clone())
-                .expect("invalid attempt to insert more than one edge counter for the same edge");
-        }
-    }
-
-    pub fn get_edge_counter(
-        &self,
-        from_bcb: BasicCoverageBlock,
-        to_bb: BasicBlock,
-    ) -> Option<&CoverageKind> {
-        if let Some(edge_to_counter) = self.some_edge_to_counter.as_ref() {
-            edge_to_counter.get(&(from_bcb, to_bb))
-        } else {
-            None
-        }
-    }
-}
-
-/// If enabled, this struct captures additional data used to track whether expressions were used,
-/// directly or indirectly, to compute the coverage counts for all `CoverageSpan`s, and any that are
-/// _not_ used are retained in the `unused_expressions` Vec, to be included in debug output (logs
-/// and/or a `CoverageGraph` graphviz output).
-pub(super) struct UsedExpressions {
-    some_used_expression_operands:
-        Option<FxHashMap<ExpressionOperandId, Vec<InjectedExpressionId>>>,
-    some_unused_expressions:
-        Option<Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)>>,
-}
-
-impl UsedExpressions {
-    pub fn new() -> Self {
-        Self { some_used_expression_operands: None, some_unused_expressions: None }
-    }
-
-    pub fn enable(&mut self) {
-        debug_assert!(!self.is_enabled());
-        self.some_used_expression_operands = Some(FxHashMap::default());
-        self.some_unused_expressions = Some(Vec::new());
-    }
-
-    pub fn is_enabled(&self) -> bool {
-        self.some_used_expression_operands.is_some()
-    }
-
-    pub fn add_expression_operands(&mut self, expression: &CoverageKind) {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_mut() {
-            if let CoverageKind::Expression { id, lhs, rhs, .. } = *expression {
-                used_expression_operands.entry(lhs).or_insert_with(Vec::new).push(id);
-                used_expression_operands.entry(rhs).or_insert_with(Vec::new).push(id);
-            }
-        }
-    }
-
-    pub fn expression_is_used(&self, expression: &CoverageKind) -> bool {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            used_expression_operands.contains_key(&expression.as_operand_id())
-        } else {
-            false
-        }
-    }
-
-    pub fn add_unused_expression_if_not_found(
-        &mut self,
-        expression: &CoverageKind,
-        edge_from_bcb: Option<BasicCoverageBlock>,
-        target_bcb: BasicCoverageBlock,
-    ) {
-        if let Some(used_expression_operands) = self.some_used_expression_operands.as_ref() {
-            if !used_expression_operands.contains_key(&expression.as_operand_id()) {
-                self.some_unused_expressions.as_mut().unwrap().push((
-                    expression.clone(),
-                    edge_from_bcb,
-                    target_bcb,
-                ));
-            }
-        }
-    }
-
-    /// Return the list of unused counters (if any) as a tuple with the counter (`CoverageKind`),
-    /// optional `from_bcb` (if it was an edge counter), and `target_bcb`.
-    pub fn get_unused_expressions(
-        &self,
-    ) -> Vec<(CoverageKind, Option<BasicCoverageBlock>, BasicCoverageBlock)> {
-        if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
-            unused_expressions.clone()
-        } else {
-            Vec::new()
-        }
-    }
-
-    /// If enabled, validate that every BCB or edge counter not directly associated with a coverage
-    /// span is at least indirectly associated (it is a dependency of a BCB counter that _is_
-    /// associated with a coverage span).
-    pub fn validate(
-        &mut self,
-        bcb_counters_without_direct_coverage_spans: &Vec<(
-            Option<BasicCoverageBlock>,
-            BasicCoverageBlock,
-            CoverageKind,
-        )>,
-    ) {
-        if self.is_enabled() {
-            let mut not_validated = bcb_counters_without_direct_coverage_spans
-                .iter()
-                .map(|(_, _, counter_kind)| counter_kind)
-                .collect::<Vec<_>>();
-            let mut validating_count = 0;
-            while not_validated.len() != validating_count {
-                let to_validate = not_validated.split_off(0);
-                validating_count = to_validate.len();
-                for counter_kind in to_validate {
-                    if self.expression_is_used(counter_kind) {
-                        self.add_expression_operands(counter_kind);
-                    } else {
-                        not_validated.push(counter_kind);
-                    }
-                }
-            }
-        }
-    }
-
-    pub fn alert_on_unused_expressions(&self, debug_counters: &DebugCounters) {
-        if let Some(unused_expressions) = self.some_unused_expressions.as_ref() {
-            for (counter_kind, edge_from_bcb, target_bcb) in unused_expressions {
-                let unused_counter_message = if let Some(from_bcb) = edge_from_bcb.as_ref() {
-                    format!(
-                        "non-coverage edge counter found without a dependent expression, in \
-                        {:?}->{:?}; counter={}",
-                        from_bcb,
-                        target_bcb,
-                        debug_counters.format_counter(&counter_kind),
-                    )
-                } else {
-                    format!(
-                        "non-coverage counter found without a dependent expression, in {:?}; \
-                        counter={}",
-                        target_bcb,
-                        debug_counters.format_counter(&counter_kind),
-                    )
-                };
-
-                if debug_options().allow_unused_expressions {
-                    debug!("WARNING: {}", unused_counter_message);
-                } else {
-                    bug!("{}", unused_counter_message);
-                }
-            }
-        }
-    }
-}
-
-/// Generates the MIR pass `CoverageSpan`-specific spanview dump file.
-pub(super) fn dump_coverage_spanview(
-    tcx: TyCtxt<'tcx>,
-    mir_body: &mir::Body<'tcx>,
-    basic_coverage_blocks: &CoverageGraph,
-    pass_name: &str,
-    body_span: Span,
-    coverage_spans: &Vec<CoverageSpan>,
-) {
-    let mir_source = mir_body.source;
-    let def_id = mir_source.def_id();
-
-    let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans);
-    let mut file = pretty::create_dump_file(tcx, "html", None, pass_name, &0, mir_source)
-        .expect("Unexpected error creating MIR spanview HTML file");
-    let crate_name = tcx.crate_name(def_id.krate);
-    let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
-    let title = format!("{}.{} - Coverage Spans", crate_name, item_name);
-    spanview::write_document(tcx, body_span, span_viewables, &title, &mut file)
-        .expect("Unexpected IO error dumping coverage spans as HTML");
-}
-
-/// Converts the computed `BasicCoverageBlockData`s into `SpanViewable`s.
-fn span_viewables(
-    tcx: TyCtxt<'tcx>,
-    mir_body: &mir::Body<'tcx>,
-    basic_coverage_blocks: &CoverageGraph,
-    coverage_spans: &Vec<CoverageSpan>,
-) -> Vec<SpanViewable> {
-    let mut span_viewables = Vec::new();
-    for coverage_span in coverage_spans {
-        let tooltip = coverage_span.format_coverage_statements(tcx, mir_body);
-        let CoverageSpan { span, bcb, .. } = coverage_span;
-        let bcb_data = &basic_coverage_blocks[*bcb];
-        let id = bcb_data.id();
-        let leader_bb = bcb_data.leader_bb();
-        span_viewables.push(SpanViewable { bb: leader_bb, span: *span, id, tooltip });
-    }
-    span_viewables
-}
-
-/// Generates the MIR pass coverage-specific graphviz dump file.
-pub(super) fn dump_coverage_graphviz(
-    tcx: TyCtxt<'tcx>,
-    mir_body: &mir::Body<'tcx>,
-    pass_name: &str,
-    basic_coverage_blocks: &CoverageGraph,
-    debug_counters: &DebugCounters,
-    graphviz_data: &GraphvizData,
-    intermediate_expressions: &Vec<CoverageKind>,
-    debug_used_expressions: &UsedExpressions,
-) {
-    let mir_source = mir_body.source;
-    let def_id = mir_source.def_id();
-    let node_content = |bcb| {
-        bcb_to_string_sections(
-            tcx,
-            mir_body,
-            debug_counters,
-            &basic_coverage_blocks[bcb],
-            graphviz_data.get_bcb_coverage_spans_with_counters(bcb),
-            graphviz_data.get_bcb_dependency_counters(bcb),
-            // intermediate_expressions are injected into the mir::START_BLOCK, so
-            // include them in the first BCB.
-            if bcb.index() == 0 { Some(&intermediate_expressions) } else { None },
-        )
-    };
-    let edge_labels = |from_bcb| {
-        let from_bcb_data = &basic_coverage_blocks[from_bcb];
-        let from_terminator = from_bcb_data.terminator(mir_body);
-        let mut edge_labels = from_terminator.kind.fmt_successor_labels();
-        edge_labels.retain(|label| label != "unreachable");
-        let edge_counters = from_terminator
-            .successors()
-            .map(|&successor_bb| graphviz_data.get_edge_counter(from_bcb, successor_bb));
-        iter::zip(&edge_labels, edge_counters)
-            .map(|(label, some_counter)| {
-                if let Some(counter) = some_counter {
-                    format!("{}\n{}", label, debug_counters.format_counter(counter))
-                } else {
-                    label.to_string()
-                }
-            })
-            .collect::<Vec<_>>()
-    };
-    let graphviz_name = format!("Cov_{}_{}", def_id.krate.index(), def_id.index.index());
-    let mut graphviz_writer =
-        GraphvizWriter::new(basic_coverage_blocks, &graphviz_name, node_content, edge_labels);
-    let unused_expressions = debug_used_expressions.get_unused_expressions();
-    if unused_expressions.len() > 0 {
-        graphviz_writer.set_graph_label(&format!(
-            "Unused expressions:\n  {}",
-            unused_expressions
-                .as_slice()
-                .iter()
-                .map(|(counter_kind, edge_from_bcb, target_bcb)| {
-                    if let Some(from_bcb) = edge_from_bcb.as_ref() {
-                        format!(
-                            "{:?}->{:?}: {}",
-                            from_bcb,
-                            target_bcb,
-                            debug_counters.format_counter(&counter_kind),
-                        )
-                    } else {
-                        format!(
-                            "{:?}: {}",
-                            target_bcb,
-                            debug_counters.format_counter(&counter_kind),
-                        )
-                    }
-                })
-                .collect::<Vec<_>>()
-                .join("\n  ")
-        ));
-    }
-    let mut file = pretty::create_dump_file(tcx, "dot", None, pass_name, &0, mir_source)
-        .expect("Unexpected error creating BasicCoverageBlock graphviz DOT file");
-    graphviz_writer
-        .write_graphviz(tcx, &mut file)
-        .expect("Unexpected error writing BasicCoverageBlock graphviz DOT file");
-}
-
-fn bcb_to_string_sections(
-    tcx: TyCtxt<'tcx>,
-    mir_body: &mir::Body<'tcx>,
-    debug_counters: &DebugCounters,
-    bcb_data: &BasicCoverageBlockData,
-    some_coverage_spans_with_counters: Option<&Vec<(CoverageSpan, CoverageKind)>>,
-    some_dependency_counters: Option<&Vec<CoverageKind>>,
-    some_intermediate_expressions: Option<&Vec<CoverageKind>>,
-) -> Vec<String> {
-    let len = bcb_data.basic_blocks.len();
-    let mut sections = Vec::new();
-    if let Some(collect_intermediate_expressions) = some_intermediate_expressions {
-        sections.push(
-            collect_intermediate_expressions
-                .iter()
-                .map(|expression| {
-                    format!("Intermediate {}", debug_counters.format_counter(expression))
-                })
-                .collect::<Vec<_>>()
-                .join("\n"),
-        );
-    }
-    if let Some(coverage_spans_with_counters) = some_coverage_spans_with_counters {
-        sections.push(
-            coverage_spans_with_counters
-                .iter()
-                .map(|(covspan, counter)| {
-                    format!(
-                        "{} at {}",
-                        debug_counters.format_counter(counter),
-                        covspan.format(tcx, mir_body)
-                    )
-                })
-                .collect::<Vec<_>>()
-                .join("\n"),
-        );
-    }
-    if let Some(dependency_counters) = some_dependency_counters {
-        sections.push(format!(
-            "Non-coverage counters:\n  {}",
-            dependency_counters
-                .iter()
-                .map(|counter| debug_counters.format_counter(counter))
-                .collect::<Vec<_>>()
-                .join("  \n"),
-        ));
-    }
-    if let Some(counter_kind) = &bcb_data.counter_kind {
-        sections.push(format!("{:?}", counter_kind));
-    }
-    let non_term_blocks = bcb_data.basic_blocks[0..len - 1]
-        .iter()
-        .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind)))
-        .collect::<Vec<_>>();
-    if non_term_blocks.len() > 0 {
-        sections.push(non_term_blocks.join("\n"));
-    }
-    sections.push(format!(
-        "{:?}: {}",
-        bcb_data.basic_blocks.last().unwrap(),
-        term_type(&bcb_data.terminator(mir_body).kind)
-    ));
-    sections
-}
-
-/// Returns a simple string representation of a `TerminatorKind` variant, independent of any
-/// values it might hold.
-pub(super) fn term_type(kind: &TerminatorKind<'tcx>) -> &'static str {
-    match kind {
-        TerminatorKind::Goto { .. } => "Goto",
-        TerminatorKind::SwitchInt { .. } => "SwitchInt",
-        TerminatorKind::Resume => "Resume",
-        TerminatorKind::Abort => "Abort",
-        TerminatorKind::Return => "Return",
-        TerminatorKind::Unreachable => "Unreachable",
-        TerminatorKind::Drop { .. } => "Drop",
-        TerminatorKind::DropAndReplace { .. } => "DropAndReplace",
-        TerminatorKind::Call { .. } => "Call",
-        TerminatorKind::Assert { .. } => "Assert",
-        TerminatorKind::Yield { .. } => "Yield",
-        TerminatorKind::GeneratorDrop => "GeneratorDrop",
-        TerminatorKind::FalseEdge { .. } => "FalseEdge",
-        TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
-        TerminatorKind::InlineAsm { .. } => "InlineAsm",
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/graph.rs b/compiler/rustc_mir/src/transform/coverage/graph.rs
deleted file mode 100644
index d78ad6ce97f..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/graph.rs
+++ /dev/null
@@ -1,769 +0,0 @@
-use super::Error;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::graph::dominators::{self, Dominators};
-use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind};
-
-use std::ops::{Index, IndexMut};
-
-const ID_SEPARATOR: &str = ",";
-
-/// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s
-/// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s, plus a
-/// `CoverageKind` counter (to be added by `CoverageCounters::make_bcb_counters`), and an optional
-/// set of additional counters--if needed--to count incoming edges, if there are more than one.
-/// (These "edge counters" are eventually converted into new MIR `BasicBlock`s.)
-#[derive(Debug)]
-pub(super) struct CoverageGraph {
-    bcbs: IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
-    bb_to_bcb: IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
-    pub successors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
-    pub predecessors: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
-    dominators: Option<Dominators<BasicCoverageBlock>>,
-}
-
-impl CoverageGraph {
-    pub fn from_mir(mir_body: &mir::Body<'tcx>) -> Self {
-        let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body);
-
-        // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock
-        // equivalents. Note that since the BasicCoverageBlock graph has been fully simplified, the
-        // each predecessor of a BCB leader_bb should be in a unique BCB. It is possible for a
-        // `SwitchInt` to have multiple targets to the same destination `BasicBlock`, so
-        // de-duplication is required. This is done without reordering the successors.
-
-        let bcbs_len = bcbs.len();
-        let mut seen = IndexVec::from_elem_n(false, bcbs_len);
-        let successors = IndexVec::from_fn_n(
-            |bcb| {
-                for b in seen.iter_mut() {
-                    *b = false;
-                }
-                let bcb_data = &bcbs[bcb];
-                let mut bcb_successors = Vec::new();
-                for successor in
-                    bcb_filtered_successors(&mir_body, &bcb_data.terminator(mir_body).kind)
-                        .filter_map(|&successor_bb| bb_to_bcb[successor_bb])
-                {
-                    if !seen[successor] {
-                        seen[successor] = true;
-                        bcb_successors.push(successor);
-                    }
-                }
-                bcb_successors
-            },
-            bcbs.len(),
-        );
-
-        let mut predecessors = IndexVec::from_elem_n(Vec::new(), bcbs.len());
-        for (bcb, bcb_successors) in successors.iter_enumerated() {
-            for &successor in bcb_successors {
-                predecessors[successor].push(bcb);
-            }
-        }
-
-        let mut basic_coverage_blocks =
-            Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None };
-        let dominators = dominators::dominators(&basic_coverage_blocks);
-        basic_coverage_blocks.dominators = Some(dominators);
-        basic_coverage_blocks
-    }
-
-    fn compute_basic_coverage_blocks(
-        mir_body: &mir::Body<'tcx>,
-    ) -> (
-        IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
-        IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
-    ) {
-        let num_basic_blocks = mir_body.num_nodes();
-        let mut bcbs = IndexVec::with_capacity(num_basic_blocks);
-        let mut bb_to_bcb = IndexVec::from_elem_n(None, num_basic_blocks);
-
-        // Walk the MIR CFG using a Preorder traversal, which starts from `START_BLOCK` and follows
-        // each block terminator's `successors()`. Coverage spans must map to actual source code,
-        // so compiler generated blocks and paths can be ignored. To that end, the CFG traversal
-        // intentionally omits unwind paths.
-        // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
-        // `catch_unwind()` handlers.
-        let mir_cfg_without_unwind = ShortCircuitPreorder::new(&mir_body, bcb_filtered_successors);
-
-        let mut basic_blocks = Vec::new();
-        for (bb, data) in mir_cfg_without_unwind {
-            if let Some(last) = basic_blocks.last() {
-                let predecessors = &mir_body.predecessors()[bb];
-                if predecessors.len() > 1 || !predecessors.contains(last) {
-                    // The `bb` has more than one _incoming_ edge, and should start its own
-                    // `BasicCoverageBlockData`. (Note, the `basic_blocks` vector does not yet
-                    // include `bb`; it contains a sequence of one or more sequential basic_blocks
-                    // with no intermediate branches in or out. Save these as a new
-                    // `BasicCoverageBlockData` before starting the new one.)
-                    Self::add_basic_coverage_block(
-                        &mut bcbs,
-                        &mut bb_to_bcb,
-                        basic_blocks.split_off(0),
-                    );
-                    debug!(
-                        "  because {}",
-                        if predecessors.len() > 1 {
-                            "predecessors.len() > 1".to_owned()
-                        } else {
-                            format!("bb {} is not in precessors: {:?}", bb.index(), predecessors)
-                        }
-                    );
-                }
-            }
-            basic_blocks.push(bb);
-
-            let term = data.terminator();
-
-            match term.kind {
-                TerminatorKind::Return { .. }
-                | TerminatorKind::Abort
-                | TerminatorKind::Yield { .. }
-                | TerminatorKind::SwitchInt { .. } => {
-                    // The `bb` has more than one _outgoing_ edge, or exits the function. Save the
-                    // current sequence of `basic_blocks` gathered to this point, as a new
-                    // `BasicCoverageBlockData`.
-                    Self::add_basic_coverage_block(
-                        &mut bcbs,
-                        &mut bb_to_bcb,
-                        basic_blocks.split_off(0),
-                    );
-                    debug!("  because term.kind = {:?}", term.kind);
-                    // Note that this condition is based on `TerminatorKind`, even though it
-                    // theoretically boils down to `successors().len() != 1`; that is, either zero
-                    // (e.g., `Return`, `Abort`) or multiple successors (e.g., `SwitchInt`), but
-                    // since the BCB CFG ignores things like unwind branches (which exist in the
-                    // `Terminator`s `successors()` list) checking the number of successors won't
-                    // work.
-                }
-
-                // The following `TerminatorKind`s are either not expected outside an unwind branch,
-                // or they should not (under normal circumstances) branch. Coverage graphs are
-                // simplified by assuring coverage results are accurate for program executions that
-                // don't panic.
-                //
-                // Programs that panic and unwind may record slightly inaccurate coverage results
-                // for a coverage region containing the `Terminator` that began the panic. This
-                // is as intended. (See Issue #78544 for a possible future option to support
-                // coverage in test programs that panic.)
-                TerminatorKind::Goto { .. }
-                | TerminatorKind::Resume
-                | TerminatorKind::Unreachable
-                | TerminatorKind::Drop { .. }
-                | TerminatorKind::DropAndReplace { .. }
-                | TerminatorKind::Call { .. }
-                | TerminatorKind::GeneratorDrop
-                | TerminatorKind::Assert { .. }
-                | TerminatorKind::FalseEdge { .. }
-                | TerminatorKind::FalseUnwind { .. }
-                | TerminatorKind::InlineAsm { .. } => {}
-            }
-        }
-
-        if !basic_blocks.is_empty() {
-            // process any remaining basic_blocks into a final `BasicCoverageBlockData`
-            Self::add_basic_coverage_block(&mut bcbs, &mut bb_to_bcb, basic_blocks.split_off(0));
-            debug!("  because the end of the MIR CFG was reached while traversing");
-        }
-
-        (bcbs, bb_to_bcb)
-    }
-
-    fn add_basic_coverage_block(
-        bcbs: &mut IndexVec<BasicCoverageBlock, BasicCoverageBlockData>,
-        bb_to_bcb: &mut IndexVec<BasicBlock, Option<BasicCoverageBlock>>,
-        basic_blocks: Vec<BasicBlock>,
-    ) {
-        let bcb = BasicCoverageBlock::from_usize(bcbs.len());
-        for &bb in basic_blocks.iter() {
-            bb_to_bcb[bb] = Some(bcb);
-        }
-        let bcb_data = BasicCoverageBlockData::from(basic_blocks);
-        debug!("adding bcb{}: {:?}", bcb.index(), bcb_data);
-        bcbs.push(bcb_data);
-    }
-
-    #[inline(always)]
-    pub fn iter_enumerated(
-        &self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, &BasicCoverageBlockData)> {
-        self.bcbs.iter_enumerated()
-    }
-
-    #[inline(always)]
-    pub fn iter_enumerated_mut(
-        &mut self,
-    ) -> impl Iterator<Item = (BasicCoverageBlock, &mut BasicCoverageBlockData)> {
-        self.bcbs.iter_enumerated_mut()
-    }
-
-    #[inline(always)]
-    pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option<BasicCoverageBlock> {
-        if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None }
-    }
-
-    #[inline(always)]
-    pub fn is_dominated_by(&self, node: BasicCoverageBlock, dom: BasicCoverageBlock) -> bool {
-        self.dominators.as_ref().unwrap().is_dominated_by(node, dom)
-    }
-
-    #[inline(always)]
-    pub fn dominators(&self) -> &Dominators<BasicCoverageBlock> {
-        self.dominators.as_ref().unwrap()
-    }
-}
-
-impl Index<BasicCoverageBlock> for CoverageGraph {
-    type Output = BasicCoverageBlockData;
-
-    #[inline]
-    fn index(&self, index: BasicCoverageBlock) -> &BasicCoverageBlockData {
-        &self.bcbs[index]
-    }
-}
-
-impl IndexMut<BasicCoverageBlock> for CoverageGraph {
-    #[inline]
-    fn index_mut(&mut self, index: BasicCoverageBlock) -> &mut BasicCoverageBlockData {
-        &mut self.bcbs[index]
-    }
-}
-
-impl graph::DirectedGraph for CoverageGraph {
-    type Node = BasicCoverageBlock;
-}
-
-impl graph::WithNumNodes for CoverageGraph {
-    #[inline]
-    fn num_nodes(&self) -> usize {
-        self.bcbs.len()
-    }
-}
-
-impl graph::WithStartNode for CoverageGraph {
-    #[inline]
-    fn start_node(&self) -> Self::Node {
-        self.bcb_from_bb(mir::START_BLOCK)
-            .expect("mir::START_BLOCK should be in a BasicCoverageBlock")
-    }
-}
-
-type BcbSuccessors<'graph> = std::slice::Iter<'graph, BasicCoverageBlock>;
-
-impl<'graph> graph::GraphSuccessors<'graph> for CoverageGraph {
-    type Item = BasicCoverageBlock;
-    type Iter = std::iter::Cloned<BcbSuccessors<'graph>>;
-}
-
-impl graph::WithSuccessors for CoverageGraph {
-    #[inline]
-    fn successors(&self, node: Self::Node) -> <Self as GraphSuccessors<'_>>::Iter {
-        self.successors[node].iter().cloned()
-    }
-}
-
-impl graph::GraphPredecessors<'graph> for CoverageGraph {
-    type Item = BasicCoverageBlock;
-    type Iter = std::iter::Copied<std::slice::Iter<'graph, BasicCoverageBlock>>;
-}
-
-impl graph::WithPredecessors for CoverageGraph {
-    #[inline]
-    fn predecessors(&self, node: Self::Node) -> <Self as graph::GraphPredecessors<'_>>::Iter {
-        self.predecessors[node].iter().copied()
-    }
-}
-
-rustc_index::newtype_index! {
-    /// A node in the [control-flow graph][CFG] of CoverageGraph.
-    pub(super) struct BasicCoverageBlock {
-        DEBUG_FORMAT = "bcb{}",
-        const START_BCB = 0,
-    }
-}
-
-/// `BasicCoverageBlockData` holds the data indexed by a `BasicCoverageBlock`.
-///
-/// A `BasicCoverageBlock` (BCB) represents the maximal-length sequence of MIR `BasicBlock`s without
-/// conditional branches, and form a new, simplified, coverage-specific Control Flow Graph, without
-/// altering the original MIR CFG.
-///
-/// Note that running the MIR `SimplifyCfg` transform is not sufficient (and therefore not
-/// necessary). The BCB-based CFG is a more aggressive simplification. For example:
-///
-///   * The BCB CFG ignores (trims) branches not relevant to coverage, such as unwind-related code,
-///     that is injected by the Rust compiler but has no physical source code to count. This also
-///     means a BasicBlock with a `Call` terminator can be merged into its primary successor target
-///     block, in the same BCB. (But, note: Issue #78544: "MIR InstrumentCoverage: Improve coverage
-///     of `#[should_panic]` tests and `catch_unwind()` handlers")
-///   * Some BasicBlock terminators support Rust-specific concerns--like borrow-checking--that are
-///     not relevant to coverage analysis. `FalseUnwind`, for example, can be treated the same as
-///     a `Goto`, and merged with its successor into the same BCB.
-///
-/// Each BCB with at least one computed `CoverageSpan` will have no more than one `Counter`.
-/// In some cases, a BCB's execution count can be computed by `Expression`. Additional
-/// disjoint `CoverageSpan`s in a BCB can also be counted by `Expression` (by adding `ZERO`
-/// to the BCB's primary counter or expression).
-///
-/// The BCB CFG is critical to simplifying the coverage analysis by ensuring graph path-based
-/// queries (`is_dominated_by()`, `predecessors`, `successors`, etc.) have branch (control flow)
-/// significance.
-#[derive(Debug, Clone)]
-pub(super) struct BasicCoverageBlockData {
-    pub basic_blocks: Vec<BasicBlock>,
-    pub counter_kind: Option<CoverageKind>,
-    edge_from_bcbs: Option<FxHashMap<BasicCoverageBlock, CoverageKind>>,
-}
-
-impl BasicCoverageBlockData {
-    pub fn from(basic_blocks: Vec<BasicBlock>) -> Self {
-        assert!(basic_blocks.len() > 0);
-        Self { basic_blocks, counter_kind: None, edge_from_bcbs: None }
-    }
-
-    #[inline(always)]
-    pub fn leader_bb(&self) -> BasicBlock {
-        self.basic_blocks[0]
-    }
-
-    #[inline(always)]
-    pub fn last_bb(&self) -> BasicBlock {
-        *self.basic_blocks.last().unwrap()
-    }
-
-    #[inline(always)]
-    pub fn terminator<'a, 'tcx>(&self, mir_body: &'a mir::Body<'tcx>) -> &'a Terminator<'tcx> {
-        &mir_body[self.last_bb()].terminator()
-    }
-
-    pub fn set_counter(
-        &mut self,
-        counter_kind: CoverageKind,
-    ) -> Result<ExpressionOperandId, Error> {
-        debug_assert!(
-            // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
-            // have an expression (to be injected into an existing `BasicBlock` represented by this
-            // `BasicCoverageBlock`).
-            self.edge_from_bcbs.is_none() || counter_kind.is_expression(),
-            "attempt to add a `Counter` to a BCB target with existing incoming edge counters"
-        );
-        let operand = counter_kind.as_operand_id();
-        if let Some(replaced) = self.counter_kind.replace(counter_kind) {
-            Error::from_string(format!(
-                "attempt to set a BasicCoverageBlock coverage counter more than once; \
-                {:?} already had counter {:?}",
-                self, replaced,
-            ))
-        } else {
-            Ok(operand)
-        }
-    }
-
-    #[inline(always)]
-    pub fn counter(&self) -> Option<&CoverageKind> {
-        self.counter_kind.as_ref()
-    }
-
-    #[inline(always)]
-    pub fn take_counter(&mut self) -> Option<CoverageKind> {
-        self.counter_kind.take()
-    }
-
-    pub fn set_edge_counter_from(
-        &mut self,
-        from_bcb: BasicCoverageBlock,
-        counter_kind: CoverageKind,
-    ) -> Result<ExpressionOperandId, Error> {
-        if level_enabled!(tracing::Level::DEBUG) {
-            // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also
-            // have an expression (to be injected into an existing `BasicBlock` represented by this
-            // `BasicCoverageBlock`).
-            if !self.counter_kind.as_ref().map_or(true, |c| c.is_expression()) {
-                return Error::from_string(format!(
-                    "attempt to add an incoming edge counter from {:?} when the target BCB already \
-                    has a `Counter`",
-                    from_bcb
-                ));
-            }
-        }
-        let operand = counter_kind.as_operand_id();
-        if let Some(replaced) =
-            self.edge_from_bcbs.get_or_insert_default().insert(from_bcb, counter_kind)
-        {
-            Error::from_string(format!(
-                "attempt to set an edge counter more than once; from_bcb: \
-                {:?} already had counter {:?}",
-                from_bcb, replaced,
-            ))
-        } else {
-            Ok(operand)
-        }
-    }
-
-    #[inline]
-    pub fn edge_counter_from(&self, from_bcb: BasicCoverageBlock) -> Option<&CoverageKind> {
-        if let Some(edge_from_bcbs) = &self.edge_from_bcbs {
-            edge_from_bcbs.get(&from_bcb)
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    pub fn take_edge_counters(
-        &mut self,
-    ) -> Option<impl Iterator<Item = (BasicCoverageBlock, CoverageKind)>> {
-        self.edge_from_bcbs.take().map_or(None, |m| Some(m.into_iter()))
-    }
-
-    pub fn id(&self) -> String {
-        format!(
-            "@{}",
-            self.basic_blocks
-                .iter()
-                .map(|bb| bb.index().to_string())
-                .collect::<Vec<_>>()
-                .join(ID_SEPARATOR)
-        )
-    }
-}
-
-/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`)
-/// as either the successor BCB itself, if it has only one incoming edge, or the successor _plus_
-/// the specific branching BCB, representing the edge between the two. The latter case
-/// distinguishes this incoming edge from other incoming edges to the same `target_bcb`.
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub(super) struct BcbBranch {
-    pub edge_from_bcb: Option<BasicCoverageBlock>,
-    pub target_bcb: BasicCoverageBlock,
-}
-
-impl BcbBranch {
-    pub fn from_to(
-        from_bcb: BasicCoverageBlock,
-        to_bcb: BasicCoverageBlock,
-        basic_coverage_blocks: &CoverageGraph,
-    ) -> Self {
-        let edge_from_bcb = if basic_coverage_blocks.predecessors[to_bcb].len() > 1 {
-            Some(from_bcb)
-        } else {
-            None
-        };
-        Self { edge_from_bcb, target_bcb: to_bcb }
-    }
-
-    pub fn counter<'a>(
-        &self,
-        basic_coverage_blocks: &'a CoverageGraph,
-    ) -> Option<&'a CoverageKind> {
-        if let Some(from_bcb) = self.edge_from_bcb {
-            basic_coverage_blocks[self.target_bcb].edge_counter_from(from_bcb)
-        } else {
-            basic_coverage_blocks[self.target_bcb].counter()
-        }
-    }
-
-    pub fn is_only_path_to_target(&self) -> bool {
-        self.edge_from_bcb.is_none()
-    }
-}
-
-impl std::fmt::Debug for BcbBranch {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        if let Some(from_bcb) = self.edge_from_bcb {
-            write!(fmt, "{:?}->{:?}", from_bcb, self.target_bcb)
-        } else {
-            write!(fmt, "{:?}", self.target_bcb)
-        }
-    }
-}
-
-// Returns the `Terminator`s non-unwind successors.
-// FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and
-// `catch_unwind()` handlers.
-fn bcb_filtered_successors<'a, 'tcx>(
-    body: &'tcx &'a mir::Body<'tcx>,
-    term_kind: &'tcx TerminatorKind<'tcx>,
-) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a> {
-    let mut successors = term_kind.successors();
-    Box::new(
-        match &term_kind {
-            // SwitchInt successors are never unwind, and all of them should be traversed.
-            TerminatorKind::SwitchInt { .. } => successors,
-            // For all other kinds, return only the first successor, if any, and ignore unwinds.
-            // NOTE: `chain(&[])` is required to coerce the `option::iter` (from
-            // `next().into_iter()`) into the `mir::Successors` aliased type.
-            _ => successors.next().into_iter().chain(&[]),
-        }
-        .filter(move |&&successor| {
-            body[successor].terminator().kind != TerminatorKind::Unreachable
-        }),
-    )
-}
-
-/// Maintains separate worklists for each loop in the BasicCoverageBlock CFG, plus one for the
-/// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that
-/// ensures a loop is completely traversed before processing Blocks after the end of the loop.
-#[derive(Debug)]
-pub(super) struct TraversalContext {
-    /// From one or more backedges returning to a loop header.
-    pub loop_backedges: Option<(Vec<BasicCoverageBlock>, BasicCoverageBlock)>,
-
-    /// worklist, to be traversed, of CoverageGraph in the loop with the given loop
-    /// backedges, such that the loop is the inner inner-most loop containing these
-    /// CoverageGraph
-    pub worklist: Vec<BasicCoverageBlock>,
-}
-
-pub(super) struct TraverseCoverageGraphWithLoops {
-    pub backedges: IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>>,
-    pub context_stack: Vec<TraversalContext>,
-    visited: BitSet<BasicCoverageBlock>,
-}
-
-impl TraverseCoverageGraphWithLoops {
-    pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self {
-        let start_bcb = basic_coverage_blocks.start_node();
-        let backedges = find_loop_backedges(basic_coverage_blocks);
-        let context_stack =
-            vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }];
-        // `context_stack` starts with a `TraversalContext` for the main function context (beginning
-        // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top
-        // of the stack as loops are entered, and popped off of the stack when a loop's worklist is
-        // exhausted.
-        let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-        Self { backedges, context_stack, visited }
-    }
-
-    pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option<BasicCoverageBlock> {
-        debug!(
-            "TraverseCoverageGraphWithLoops::next - context_stack: {:?}",
-            self.context_stack.iter().rev().collect::<Vec<_>>()
-        );
-        while let Some(next_bcb) = {
-            // Strip contexts with empty worklists from the top of the stack
-            while self.context_stack.last().map_or(false, |context| context.worklist.is_empty()) {
-                self.context_stack.pop();
-            }
-            // Pop the next bcb off of the current context_stack. If none, all BCBs were visited.
-            self.context_stack.last_mut().map_or(None, |context| context.worklist.pop())
-        } {
-            if !self.visited.insert(next_bcb) {
-                debug!("Already visited: {:?}", next_bcb);
-                continue;
-            }
-            debug!("Visiting {:?}", next_bcb);
-            if self.backedges[next_bcb].len() > 0 {
-                debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb);
-                self.context_stack.push(TraversalContext {
-                    loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)),
-                    worklist: Vec::new(),
-                });
-            }
-            self.extend_worklist(basic_coverage_blocks, next_bcb);
-            return Some(next_bcb);
-        }
-        None
-    }
-
-    pub fn extend_worklist(
-        &mut self,
-        basic_coverage_blocks: &CoverageGraph,
-        bcb: BasicCoverageBlock,
-    ) {
-        let successors = &basic_coverage_blocks.successors[bcb];
-        debug!("{:?} has {} successors:", bcb, successors.len());
-        for &successor in successors {
-            if successor == bcb {
-                debug!(
-                    "{:?} has itself as its own successor. (Note, the compiled code will \
-                    generate an infinite loop.)",
-                    bcb
-                );
-                // Don't re-add this successor to the worklist. We are already processing it.
-                break;
-            }
-            for context in self.context_stack.iter_mut().rev() {
-                // Add successors of the current BCB to the appropriate context. Successors that
-                // stay within a loop are added to the BCBs context worklist. Successors that
-                // exit the loop (they are not dominated by the loop header) must be reachable
-                // from other BCBs outside the loop, and they will be added to a different
-                // worklist.
-                //
-                // Branching blocks (with more than one successor) must be processed before
-                // blocks with only one successor, to prevent unnecessarily complicating
-                // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the
-                // branching block would have given an `Expression` (or vice versa).
-                let (some_successor_to_add, some_loop_header) =
-                    if let Some((_, loop_header)) = context.loop_backedges {
-                        if basic_coverage_blocks.is_dominated_by(successor, loop_header) {
-                            (Some(successor), Some(loop_header))
-                        } else {
-                            (None, None)
-                        }
-                    } else {
-                        (Some(successor), None)
-                    };
-                if let Some(successor_to_add) = some_successor_to_add {
-                    if basic_coverage_blocks.successors[successor_to_add].len() > 1 {
-                        debug!(
-                            "{:?} successor is branching. Prioritize it at the beginning of \
-                            the {}",
-                            successor_to_add,
-                            if let Some(loop_header) = some_loop_header {
-                                format!("worklist for the loop headed by {:?}", loop_header)
-                            } else {
-                                String::from("non-loop worklist")
-                            },
-                        );
-                        context.worklist.insert(0, successor_to_add);
-                    } else {
-                        debug!(
-                            "{:?} successor is non-branching. Defer it to the end of the {}",
-                            successor_to_add,
-                            if let Some(loop_header) = some_loop_header {
-                                format!("worklist for the loop headed by {:?}", loop_header)
-                            } else {
-                                String::from("non-loop worklist")
-                            },
-                        );
-                        context.worklist.push(successor_to_add);
-                    }
-                    break;
-                }
-            }
-        }
-    }
-
-    pub fn is_complete(&self) -> bool {
-        self.visited.count() == self.visited.domain_size()
-    }
-
-    pub fn unvisited(&self) -> Vec<BasicCoverageBlock> {
-        let mut unvisited_set: BitSet<BasicCoverageBlock> =
-            BitSet::new_filled(self.visited.domain_size());
-        unvisited_set.subtract(&self.visited);
-        unvisited_set.iter().collect::<Vec<_>>()
-    }
-}
-
-pub(super) fn find_loop_backedges(
-    basic_coverage_blocks: &CoverageGraph,
-) -> IndexVec<BasicCoverageBlock, Vec<BasicCoverageBlock>> {
-    let num_bcbs = basic_coverage_blocks.num_nodes();
-    let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs);
-
-    // Identify loops by their backedges.
-    //
-    // The computational complexity is bounded by: n(s) x d where `n` is the number of
-    // `BasicCoverageBlock` nodes (the simplified/reduced representation of the CFG derived from the
-    // MIR); `s` is the average number of successors per node (which is most likely less than 2, and
-    // independent of the size of the function, so it can be treated as a constant);
-    // and `d` is the average number of dominators per node.
-    //
-    // The average number of dominators depends on the size and complexity of the function, and
-    // nodes near the start of the function's control flow graph typically have less dominators
-    // than nodes near the end of the CFG. Without doing a detailed mathematical analysis, I
-    // think the resulting complexity has the characteristics of O(n log n).
-    //
-    // The overall complexity appears to be comparable to many other MIR transform algorithms, and I
-    // don't expect that this function is creating a performance hot spot, but if this becomes an
-    // issue, there may be ways to optimize the `is_dominated_by` algorithm (as indicated by an
-    // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps
-    // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short
-    // circuit downstream `is_dominated_by` checks.
-    //
-    // For now, that kind of optimization seems unnecessarily complicated.
-    for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
-        for &successor in &basic_coverage_blocks.successors[bcb] {
-            if basic_coverage_blocks.is_dominated_by(bcb, successor) {
-                let loop_header = successor;
-                let backedge_from_bcb = bcb;
-                debug!(
-                    "Found BCB backedge: {:?} -> loop_header: {:?}",
-                    backedge_from_bcb, loop_header
-                );
-                backedges[loop_header].push(backedge_from_bcb);
-            }
-        }
-    }
-    backedges
-}
-
-pub struct ShortCircuitPreorder<
-    'a,
-    'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
-> {
-    body: &'tcx &'a mir::Body<'tcx>,
-    visited: BitSet<BasicBlock>,
-    worklist: Vec<BasicBlock>,
-    filtered_successors: F,
-}
-
-impl<
-    'a,
-    'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
-> ShortCircuitPreorder<'a, 'tcx, F>
-{
-    pub fn new(
-        body: &'tcx &'a mir::Body<'tcx>,
-        filtered_successors: F,
-    ) -> ShortCircuitPreorder<'a, 'tcx, F> {
-        let worklist = vec![mir::START_BLOCK];
-
-        ShortCircuitPreorder {
-            body,
-            visited: BitSet::new_empty(body.basic_blocks().len()),
-            worklist,
-            filtered_successors,
-        }
-    }
-}
-
-impl<
-    'a: 'tcx,
-    'tcx,
-    F: Fn(
-        &'tcx &'a mir::Body<'tcx>,
-        &'tcx TerminatorKind<'tcx>,
-    ) -> Box<dyn Iterator<Item = &'a BasicBlock> + 'a>,
-> Iterator for ShortCircuitPreorder<'a, 'tcx, F>
-{
-    type Item = (BasicBlock, &'a BasicBlockData<'tcx>);
-
-    fn next(&mut self) -> Option<(BasicBlock, &'a BasicBlockData<'tcx>)> {
-        while let Some(idx) = self.worklist.pop() {
-            if !self.visited.insert(idx) {
-                continue;
-            }
-
-            let data = &self.body[idx];
-
-            if let Some(ref term) = data.terminator {
-                self.worklist.extend((self.filtered_successors)(&self.body, &term.kind));
-            }
-
-            return Some((idx, data));
-        }
-
-        None
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        let size = self.body.basic_blocks().len() - self.visited.count();
-        (size, Some(size))
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/mod.rs b/compiler/rustc_mir/src/transform/coverage/mod.rs
deleted file mode 100644
index f7fbea6ad53..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/mod.rs
+++ /dev/null
@@ -1,588 +0,0 @@
-pub mod query;
-
-mod counters;
-mod debug;
-mod graph;
-mod spans;
-
-#[cfg(test)]
-mod tests;
-
-use counters::CoverageCounters;
-use graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph};
-use spans::{CoverageSpan, CoverageSpans};
-
-use crate::transform::MirPass;
-use crate::util::pretty;
-
-use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::graph::WithNumNodes;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::Lrc;
-use rustc_index::vec::IndexVec;
-use rustc_middle::hir;
-use rustc_middle::hir::map::blocks::FnLikeNode;
-use rustc_middle::ich::StableHashingContext;
-use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{
-    self, BasicBlock, BasicBlockData, Coverage, SourceInfo, Statement, StatementKind, Terminator,
-    TerminatorKind,
-};
-use rustc_middle::ty::TyCtxt;
-use rustc_span::def_id::DefId;
-use rustc_span::source_map::SourceMap;
-use rustc_span::{CharPos, ExpnKind, Pos, SourceFile, Span, Symbol};
-
-/// A simple error message wrapper for `coverage::Error`s.
-#[derive(Debug)]
-struct Error {
-    message: String,
-}
-
-impl Error {
-    pub fn from_string<T>(message: String) -> Result<T, Error> {
-        Err(Self { message })
-    }
-}
-
-/// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
-/// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
-/// to construct the coverage map.
-pub struct InstrumentCoverage;
-
-impl<'tcx> MirPass<'tcx> for InstrumentCoverage {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) {
-        let mir_source = mir_body.source;
-
-        // If the InstrumentCoverage pass is called on promoted MIRs, skip them.
-        // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601
-        if mir_source.promoted.is_some() {
-            trace!(
-                "InstrumentCoverage skipped for {:?} (already promoted for Miri evaluation)",
-                mir_source.def_id()
-            );
-            return;
-        }
-
-        let hir_id = tcx.hir().local_def_id_to_hir_id(mir_source.def_id().expect_local());
-        let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
-
-        // Only instrument functions, methods, and closures (not constants since they are evaluated
-        // at compile time by Miri).
-        // FIXME(#73156): Handle source code coverage in const eval, but note, if and when const
-        // expressions get coverage spans, we will probably have to "carve out" space for const
-        // expressions from coverage spans in enclosing MIR's, like we do for closures. (That might
-        // be tricky if const expressions have no corresponding statements in the enclosing MIR.
-        // Closures are carved out by their initial `Assign` statement.)
-        if !is_fn_like {
-            trace!("InstrumentCoverage skipped for {:?} (not an FnLikeNode)", mir_source.def_id());
-            return;
-        }
-
-        match mir_body.basic_blocks()[mir::START_BLOCK].terminator().kind {
-            TerminatorKind::Unreachable => {
-                trace!("InstrumentCoverage skipped for unreachable `START_BLOCK`");
-                return;
-            }
-            _ => {}
-        }
-
-        let codegen_fn_attrs = tcx.codegen_fn_attrs(mir_source.def_id());
-        if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NO_COVERAGE) {
-            return;
-        }
-
-        trace!("InstrumentCoverage starting for {:?}", mir_source.def_id());
-        Instrumentor::new(&self.name(), tcx, mir_body).inject_counters();
-        trace!("InstrumentCoverage done for {:?}", mir_source.def_id());
-    }
-}
-
-struct Instrumentor<'a, 'tcx> {
-    pass_name: &'a str,
-    tcx: TyCtxt<'tcx>,
-    mir_body: &'a mut mir::Body<'tcx>,
-    source_file: Lrc<SourceFile>,
-    fn_sig_span: Span,
-    body_span: Span,
-    basic_coverage_blocks: CoverageGraph,
-    coverage_counters: CoverageCounters,
-}
-
-impl<'a, 'tcx> Instrumentor<'a, 'tcx> {
-    fn new(pass_name: &'a str, tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self {
-        let source_map = tcx.sess.source_map();
-        let def_id = mir_body.source.def_id();
-        let (some_fn_sig, hir_body) = fn_sig_and_body(tcx, def_id);
-
-        let body_span = get_body_span(tcx, hir_body, mir_body);
-
-        let source_file = source_map.lookup_source_file(body_span.lo());
-        let fn_sig_span = match some_fn_sig.filter(|fn_sig| {
-            fn_sig.span.ctxt() == body_span.ctxt()
-                && Lrc::ptr_eq(&source_file, &source_map.lookup_source_file(fn_sig.span.lo()))
-        }) {
-            Some(fn_sig) => fn_sig.span.with_hi(body_span.lo()),
-            None => body_span.shrink_to_lo(),
-        };
-
-        debug!(
-            "instrumenting {}: {:?}, fn sig span: {:?}, body span: {:?}",
-            if tcx.is_closure(def_id) { "closure" } else { "function" },
-            def_id,
-            fn_sig_span,
-            body_span
-        );
-
-        let function_source_hash = hash_mir_source(tcx, hir_body);
-        let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
-        Self {
-            pass_name,
-            tcx,
-            mir_body,
-            source_file,
-            fn_sig_span,
-            body_span,
-            basic_coverage_blocks,
-            coverage_counters: CoverageCounters::new(function_source_hash),
-        }
-    }
-
-    fn inject_counters(&'a mut self) {
-        let tcx = self.tcx;
-        let mir_source = self.mir_body.source;
-        let def_id = mir_source.def_id();
-        let fn_sig_span = self.fn_sig_span;
-        let body_span = self.body_span;
-
-        let mut graphviz_data = debug::GraphvizData::new();
-        let mut debug_used_expressions = debug::UsedExpressions::new();
-
-        let dump_mir = pretty::dump_enabled(tcx, self.pass_name, def_id);
-        let dump_graphviz = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_graphviz;
-        let dump_spanview = dump_mir && tcx.sess.opts.debugging_opts.dump_mir_spanview.is_some();
-
-        if dump_graphviz {
-            graphviz_data.enable();
-            self.coverage_counters.enable_debug();
-        }
-
-        if dump_graphviz || level_enabled!(tracing::Level::DEBUG) {
-            debug_used_expressions.enable();
-        }
-
-        ////////////////////////////////////////////////////
-        // Compute `CoverageSpan`s from the `CoverageGraph`.
-        let coverage_spans = CoverageSpans::generate_coverage_spans(
-            &self.mir_body,
-            fn_sig_span,
-            body_span,
-            &self.basic_coverage_blocks,
-        );
-
-        if dump_spanview {
-            debug::dump_coverage_spanview(
-                tcx,
-                self.mir_body,
-                &self.basic_coverage_blocks,
-                self.pass_name,
-                body_span,
-                &coverage_spans,
-            );
-        }
-
-        ////////////////////////////////////////////////////
-        // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
-        // every `CoverageSpan` has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
-        // and all `Expression` dependencies (operands) are also generated, for any other
-        // `BasicCoverageBlock`s not already associated with a `CoverageSpan`.
-        //
-        // Intermediate expressions (used to compute other `Expression` values), which have no
-        // direct associate to any `BasicCoverageBlock`, are returned in the method `Result`.
-        let intermediate_expressions_or_error = self
-            .coverage_counters
-            .make_bcb_counters(&mut self.basic_coverage_blocks, &coverage_spans);
-
-        let (result, intermediate_expressions) = match intermediate_expressions_or_error {
-            Ok(intermediate_expressions) => {
-                // If debugging, add any intermediate expressions (which are not associated with any
-                // BCB) to the `debug_used_expressions` map.
-                if debug_used_expressions.is_enabled() {
-                    for intermediate_expression in &intermediate_expressions {
-                        debug_used_expressions.add_expression_operands(intermediate_expression);
-                    }
-                }
-
-                ////////////////////////////////////////////////////
-                // Remove the counter or edge counter from of each `CoverageSpan`s associated
-                // `BasicCoverageBlock`, and inject a `Coverage` statement into the MIR.
-                //
-                // `Coverage` statements injected from `CoverageSpan`s will include the code regions
-                // (source code start and end positions) to be counted by the associated counter.
-                //
-                // These `CoverageSpan`-associated counters are removed from their associated
-                // `BasicCoverageBlock`s so that the only remaining counters in the `CoverageGraph`
-                // are indirect counters (to be injected next, without associated code regions).
-                self.inject_coverage_span_counters(
-                    coverage_spans,
-                    &mut graphviz_data,
-                    &mut debug_used_expressions,
-                );
-
-                ////////////////////////////////////////////////////
-                // For any remaining `BasicCoverageBlock` counters (that were not associated with
-                // any `CoverageSpan`), inject `Coverage` statements (_without_ code region `Span`s)
-                // to ensure `BasicCoverageBlock` counters that other `Expression`s may depend on
-                // are in fact counted, even though they don't directly contribute to counting
-                // their own independent code region's coverage.
-                self.inject_indirect_counters(&mut graphviz_data, &mut debug_used_expressions);
-
-                // Intermediate expressions will be injected as the final step, after generating
-                // debug output, if any.
-                ////////////////////////////////////////////////////
-
-                (Ok(()), intermediate_expressions)
-            }
-            Err(e) => (Err(e), Vec::new()),
-        };
-
-        if graphviz_data.is_enabled() {
-            // Even if there was an error, a partial CoverageGraph can still generate a useful
-            // graphviz output.
-            debug::dump_coverage_graphviz(
-                tcx,
-                self.mir_body,
-                self.pass_name,
-                &self.basic_coverage_blocks,
-                &self.coverage_counters.debug_counters,
-                &graphviz_data,
-                &intermediate_expressions,
-                &debug_used_expressions,
-            );
-        }
-
-        if let Err(e) = result {
-            bug!("Error processing: {:?}: {:?}", self.mir_body.source.def_id(), e)
-        };
-
-        // Depending on current `debug_options()`, `alert_on_unused_expressions()` could panic, so
-        // this check is performed as late as possible, to allow other debug output (logs and dump
-        // files), which might be helpful in analyzing unused expressions, to still be generated.
-        debug_used_expressions.alert_on_unused_expressions(&self.coverage_counters.debug_counters);
-
-        ////////////////////////////////////////////////////
-        // Finally, inject the intermediate expressions collected along the way.
-        for intermediate_expression in intermediate_expressions {
-            inject_intermediate_expression(self.mir_body, intermediate_expression);
-        }
-    }
-
-    /// Inject a counter for each `CoverageSpan`. There can be multiple `CoverageSpan`s for a given
-    /// BCB, but only one actual counter needs to be incremented per BCB. `bb_counters` maps each
-    /// `bcb` to its `Counter`, when injected. Subsequent `CoverageSpan`s for a BCB that already has
-    /// a `Counter` will inject an `Expression` instead, and compute its value by adding `ZERO` to
-    /// the BCB `Counter` value.
-    ///
-    /// If debugging, add every BCB `Expression` associated with a `CoverageSpan`s to the
-    /// `used_expression_operands` map.
-    fn inject_coverage_span_counters(
-        &mut self,
-        coverage_spans: Vec<CoverageSpan>,
-        graphviz_data: &mut debug::GraphvizData,
-        debug_used_expressions: &mut debug::UsedExpressions,
-    ) {
-        let tcx = self.tcx;
-        let source_map = tcx.sess.source_map();
-        let body_span = self.body_span;
-        let file_name = Symbol::intern(&self.source_file.name.prefer_remapped().to_string_lossy());
-
-        let mut bcb_counters = IndexVec::from_elem_n(None, self.basic_coverage_blocks.num_nodes());
-        for covspan in coverage_spans {
-            let bcb = covspan.bcb;
-            let span = covspan.span;
-            let counter_kind = if let Some(&counter_operand) = bcb_counters[bcb].as_ref() {
-                self.coverage_counters.make_identity_counter(counter_operand)
-            } else if let Some(counter_kind) = self.bcb_data_mut(bcb).take_counter() {
-                bcb_counters[bcb] = Some(counter_kind.as_operand_id());
-                debug_used_expressions.add_expression_operands(&counter_kind);
-                counter_kind
-            } else {
-                bug!("Every BasicCoverageBlock should have a Counter or Expression");
-            };
-            graphviz_data.add_bcb_coverage_span_with_counter(bcb, &covspan, &counter_kind);
-
-            debug!(
-                "Calling make_code_region(file_name={}, source_file={:?}, span={}, body_span={})",
-                file_name,
-                self.source_file,
-                source_map.span_to_diagnostic_string(span),
-                source_map.span_to_diagnostic_string(body_span)
-            );
-
-            inject_statement(
-                self.mir_body,
-                counter_kind,
-                self.bcb_leader_bb(bcb),
-                Some(make_code_region(source_map, file_name, &self.source_file, span, body_span)),
-            );
-        }
-    }
-
-    /// `inject_coverage_span_counters()` looped through the `CoverageSpan`s and injected the
-    /// counter from the `CoverageSpan`s `BasicCoverageBlock`, removing it from the BCB in the
-    /// process (via `take_counter()`).
-    ///
-    /// Any other counter associated with a `BasicCoverageBlock`, or its incoming edge, but not
-    /// associated with a `CoverageSpan`, should only exist if the counter is an `Expression`
-    /// dependency (one of the expression operands). Collect them, and inject the additional
-    /// counters into the MIR, without a reportable coverage span.
-    fn inject_indirect_counters(
-        &mut self,
-        graphviz_data: &mut debug::GraphvizData,
-        debug_used_expressions: &mut debug::UsedExpressions,
-    ) {
-        let mut bcb_counters_without_direct_coverage_spans = Vec::new();
-        for (target_bcb, target_bcb_data) in self.basic_coverage_blocks.iter_enumerated_mut() {
-            if let Some(counter_kind) = target_bcb_data.take_counter() {
-                bcb_counters_without_direct_coverage_spans.push((None, target_bcb, counter_kind));
-            }
-            if let Some(edge_counters) = target_bcb_data.take_edge_counters() {
-                for (from_bcb, counter_kind) in edge_counters {
-                    bcb_counters_without_direct_coverage_spans.push((
-                        Some(from_bcb),
-                        target_bcb,
-                        counter_kind,
-                    ));
-                }
-            }
-        }
-
-        // If debug is enabled, validate that every BCB or edge counter not directly associated
-        // with a coverage span is at least indirectly associated (it is a dependency of a BCB
-        // counter that _is_ associated with a coverage span).
-        debug_used_expressions.validate(&bcb_counters_without_direct_coverage_spans);
-
-        for (edge_from_bcb, target_bcb, counter_kind) in bcb_counters_without_direct_coverage_spans
-        {
-            debug_used_expressions.add_unused_expression_if_not_found(
-                &counter_kind,
-                edge_from_bcb,
-                target_bcb,
-            );
-
-            match counter_kind {
-                CoverageKind::Counter { .. } => {
-                    let inject_to_bb = if let Some(from_bcb) = edge_from_bcb {
-                        // The MIR edge starts `from_bb` (the outgoing / last BasicBlock in
-                        // `from_bcb`) and ends at `to_bb` (the incoming / first BasicBlock in the
-                        // `target_bcb`; also called the `leader_bb`).
-                        let from_bb = self.bcb_last_bb(from_bcb);
-                        let to_bb = self.bcb_leader_bb(target_bcb);
-
-                        let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb);
-                        graphviz_data.set_edge_counter(from_bcb, new_bb, &counter_kind);
-                        debug!(
-                            "Edge {:?} (last {:?}) -> {:?} (leader {:?}) requires a new MIR \
-                            BasicBlock {:?}, for unclaimed edge counter {}",
-                            edge_from_bcb,
-                            from_bb,
-                            target_bcb,
-                            to_bb,
-                            new_bb,
-                            self.format_counter(&counter_kind),
-                        );
-                        new_bb
-                    } else {
-                        let target_bb = self.bcb_last_bb(target_bcb);
-                        graphviz_data.add_bcb_dependency_counter(target_bcb, &counter_kind);
-                        debug!(
-                            "{:?} ({:?}) gets a new Coverage statement for unclaimed counter {}",
-                            target_bcb,
-                            target_bb,
-                            self.format_counter(&counter_kind),
-                        );
-                        target_bb
-                    };
-
-                    inject_statement(self.mir_body, counter_kind, inject_to_bb, None);
-                }
-                CoverageKind::Expression { .. } => {
-                    inject_intermediate_expression(self.mir_body, counter_kind)
-                }
-                _ => bug!("CoverageKind should be a counter"),
-            }
-        }
-    }
-
-    #[inline]
-    fn bcb_leader_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
-        self.bcb_data(bcb).leader_bb()
-    }
-
-    #[inline]
-    fn bcb_last_bb(&self, bcb: BasicCoverageBlock) -> BasicBlock {
-        self.bcb_data(bcb).last_bb()
-    }
-
-    #[inline]
-    fn bcb_data(&self, bcb: BasicCoverageBlock) -> &BasicCoverageBlockData {
-        &self.basic_coverage_blocks[bcb]
-    }
-
-    #[inline]
-    fn bcb_data_mut(&mut self, bcb: BasicCoverageBlock) -> &mut BasicCoverageBlockData {
-        &mut self.basic_coverage_blocks[bcb]
-    }
-
-    #[inline]
-    fn format_counter(&self, counter_kind: &CoverageKind) -> String {
-        self.coverage_counters.debug_counters.format_counter(counter_kind)
-    }
-}
-
-fn inject_edge_counter_basic_block(
-    mir_body: &mut mir::Body<'tcx>,
-    from_bb: BasicBlock,
-    to_bb: BasicBlock,
-) -> BasicBlock {
-    let span = mir_body[from_bb].terminator().source_info.span.shrink_to_hi();
-    let new_bb = mir_body.basic_blocks_mut().push(BasicBlockData {
-        statements: vec![], // counter will be injected here
-        terminator: Some(Terminator {
-            source_info: SourceInfo::outermost(span),
-            kind: TerminatorKind::Goto { target: to_bb },
-        }),
-        is_cleanup: false,
-    });
-    let edge_ref = mir_body[from_bb]
-        .terminator_mut()
-        .successors_mut()
-        .find(|successor| **successor == to_bb)
-        .expect("from_bb should have a successor for to_bb");
-    *edge_ref = new_bb;
-    new_bb
-}
-
-fn inject_statement(
-    mir_body: &mut mir::Body<'tcx>,
-    counter_kind: CoverageKind,
-    bb: BasicBlock,
-    some_code_region: Option<CodeRegion>,
-) {
-    debug!(
-        "  injecting statement {:?} for {:?} at code region: {:?}",
-        counter_kind, bb, some_code_region
-    );
-    let data = &mut mir_body[bb];
-    let source_info = data.terminator().source_info;
-    let statement = Statement {
-        source_info,
-        kind: StatementKind::Coverage(Box::new(Coverage {
-            kind: counter_kind,
-            code_region: some_code_region,
-        })),
-    };
-    data.statements.insert(0, statement);
-}
-
-// Non-code expressions are injected into the coverage map, without generating executable code.
-fn inject_intermediate_expression(mir_body: &mut mir::Body<'tcx>, expression: CoverageKind) {
-    debug_assert!(if let CoverageKind::Expression { .. } = expression { true } else { false });
-    debug!("  injecting non-code expression {:?}", expression);
-    let inject_in_bb = mir::START_BLOCK;
-    let data = &mut mir_body[inject_in_bb];
-    let source_info = data.terminator().source_info;
-    let statement = Statement {
-        source_info,
-        kind: StatementKind::Coverage(Box::new(Coverage { kind: expression, code_region: None })),
-    };
-    data.statements.push(statement);
-}
-
-/// Convert the Span into its file name, start line and column, and end line and column
-fn make_code_region(
-    source_map: &SourceMap,
-    file_name: Symbol,
-    source_file: &Lrc<SourceFile>,
-    span: Span,
-    body_span: Span,
-) -> CodeRegion {
-    let (start_line, mut start_col) = source_file.lookup_file_pos(span.lo());
-    let (end_line, end_col) = if span.hi() == span.lo() {
-        let (end_line, mut end_col) = (start_line, start_col);
-        // Extend an empty span by one character so the region will be counted.
-        let CharPos(char_pos) = start_col;
-        if span.hi() == body_span.hi() {
-            start_col = CharPos(char_pos - 1);
-        } else {
-            end_col = CharPos(char_pos + 1);
-        }
-        (end_line, end_col)
-    } else {
-        source_file.lookup_file_pos(span.hi())
-    };
-    let start_line = source_map.doctest_offset_line(&source_file.name, start_line);
-    let end_line = source_map.doctest_offset_line(&source_file.name, end_line);
-    CodeRegion {
-        file_name,
-        start_line: start_line as u32,
-        start_col: start_col.to_u32() + 1,
-        end_line: end_line as u32,
-        end_col: end_col.to_u32() + 1,
-    }
-}
-
-fn fn_sig_and_body<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def_id: DefId,
-) -> (Option<&'tcx rustc_hir::FnSig<'tcx>>, &'tcx rustc_hir::Body<'tcx>) {
-    // FIXME(#79625): Consider improving MIR to provide the information needed, to avoid going back
-    // to HIR for it.
-    let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local");
-    let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body");
-    (hir::map::fn_sig(hir_node), tcx.hir().body(fn_body_id))
-}
-
-fn get_body_span<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    hir_body: &rustc_hir::Body<'tcx>,
-    mir_body: &mut mir::Body<'tcx>,
-) -> Span {
-    let mut body_span = hir_body.value.span;
-    let def_id = mir_body.source.def_id();
-
-    if tcx.is_closure(def_id) {
-        // If the MIR function is a closure, and if the closure body span
-        // starts from a macro, but it's content is not in that macro, try
-        // to find a non-macro callsite, and instrument the spans there
-        // instead.
-        loop {
-            let expn_data = body_span.ctxt().outer_expn_data();
-            if expn_data.is_root() {
-                break;
-            }
-            if let ExpnKind::Macro { .. } = expn_data.kind {
-                body_span = expn_data.call_site;
-            } else {
-                break;
-            }
-        }
-    }
-
-    body_span
-}
-
-fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
-    let mut hcx = tcx.create_no_span_stable_hashing_context();
-    hash(&mut hcx, &hir_body.value).to_smaller_hash()
-}
-
-fn hash(
-    hcx: &mut StableHashingContext<'tcx>,
-    node: &impl HashStable<StableHashingContext<'tcx>>,
-) -> Fingerprint {
-    let mut stable_hasher = StableHasher::new();
-    node.hash_stable(hcx, &mut stable_hasher);
-    stable_hasher.finish()
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/query.rs b/compiler/rustc_mir/src/transform/coverage/query.rs
deleted file mode 100644
index 760f16eae6b..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/query.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-use super::*;
-
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{self, Body, Coverage, CoverageInfo};
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::def_id::DefId;
-
-/// A `query` provider for retrieving coverage information injected into MIR.
-pub(crate) fn provide(providers: &mut Providers) {
-    providers.coverageinfo = |tcx, def_id| coverageinfo(tcx, def_id);
-    providers.covered_file_name = |tcx, def_id| covered_file_name(tcx, def_id);
-    providers.covered_code_regions = |tcx, def_id| covered_code_regions(tcx, def_id);
-}
-
-/// The `num_counters` argument to `llvm.instrprof.increment` is the max counter_id + 1, or in
-/// other words, the number of counter value references injected into the MIR (plus 1 for the
-/// reserved `ZERO` counter, which uses counter ID `0` when included in an expression). Injected
-/// counters have a counter ID from `1..num_counters-1`.
-///
-/// `num_expressions` is the number of counter expressions added to the MIR body.
-///
-/// Both `num_counters` and `num_expressions` are used to initialize new vectors, during backend
-/// code generate, to lookup counters and expressions by simple u32 indexes.
-///
-/// MIR optimization may split and duplicate some BasicBlock sequences, or optimize out some code
-/// including injected counters. (It is OK if some counters are optimized out, but those counters
-/// are still included in the total `num_counters` or `num_expressions`.) Simply counting the
-/// calls may not work; but computing the number of counters or expressions by adding `1` to the
-/// highest ID (for a given instrumented function) is valid.
-///
-/// This visitor runs twice, first with `add_missing_operands` set to `false`, to find the maximum
-/// counter ID and maximum expression ID based on their enum variant `id` fields; then, as a
-/// safeguard, with `add_missing_operands` set to `true`, to find any other counter or expression
-/// IDs referenced by expression operands, if not already seen.
-///
-/// Ideally, each operand ID in a MIR `CoverageKind::Expression` will have a separate MIR `Coverage`
-/// statement for the `Counter` or `Expression` with the referenced ID. but since current or future
-/// MIR optimizations can theoretically optimize out segments of a MIR, it may not be possible to
-/// guarantee this, so the second pass ensures the `CoverageInfo` counts include all referenced IDs.
-struct CoverageVisitor {
-    info: CoverageInfo,
-    add_missing_operands: bool,
-}
-
-impl CoverageVisitor {
-    /// Updates `num_counters` to the maximum encountered zero-based counter_id plus 1. Note the
-    /// final computed number of counters should be the number of all `CoverageKind::Counter`
-    /// statements in the MIR *plus one* for the implicit `ZERO` counter.
-    #[inline(always)]
-    fn update_num_counters(&mut self, counter_id: u32) {
-        self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1);
-    }
-
-    /// Computes an expression index for each expression ID, and updates `num_expressions` to the
-    /// maximum encountered index plus 1.
-    #[inline(always)]
-    fn update_num_expressions(&mut self, expression_id: u32) {
-        let expression_index = u32::MAX - expression_id;
-        self.info.num_expressions = std::cmp::max(self.info.num_expressions, expression_index + 1);
-    }
-
-    fn update_from_expression_operand(&mut self, operand_id: u32) {
-        if operand_id >= self.info.num_counters {
-            let operand_as_expression_index = u32::MAX - operand_id;
-            if operand_as_expression_index >= self.info.num_expressions {
-                // The operand ID is outside the known range of counter IDs and also outside the
-                // known range of expression IDs. In either case, the result of a missing operand
-                // (if and when used in an expression) will be zero, so from a computation
-                // perspective, it doesn't matter whether it is interepretted as a counter or an
-                // expression.
-                //
-                // However, the `num_counters` and `num_expressions` query results are used to
-                // allocate arrays when generating the coverage map (during codegen), so choose
-                // the type that grows either `num_counters` or `num_expressions` the least.
-                if operand_id - self.info.num_counters
-                    < operand_as_expression_index - self.info.num_expressions
-                {
-                    self.update_num_counters(operand_id)
-                } else {
-                    self.update_num_expressions(operand_id)
-                }
-            }
-        }
-    }
-
-    fn visit_body(&mut self, body: &Body<'_>) {
-        for bb_data in body.basic_blocks().iter() {
-            for statement in bb_data.statements.iter() {
-                if let StatementKind::Coverage(box ref coverage) = statement.kind {
-                    if is_inlined(body, statement) {
-                        continue;
-                    }
-                    self.visit_coverage(coverage);
-                }
-            }
-        }
-    }
-
-    fn visit_coverage(&mut self, coverage: &Coverage) {
-        if self.add_missing_operands {
-            match coverage.kind {
-                CoverageKind::Expression { lhs, rhs, .. } => {
-                    self.update_from_expression_operand(u32::from(lhs));
-                    self.update_from_expression_operand(u32::from(rhs));
-                }
-                _ => {}
-            }
-        } else {
-            match coverage.kind {
-                CoverageKind::Counter { id, .. } => {
-                    self.update_num_counters(u32::from(id));
-                }
-                CoverageKind::Expression { id, .. } => {
-                    self.update_num_expressions(u32::from(id));
-                }
-                _ => {}
-            }
-        }
-    }
-}
-
-fn coverageinfo<'tcx>(tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>) -> CoverageInfo {
-    let mir_body = tcx.instance_mir(instance_def);
-
-    let mut coverage_visitor = CoverageVisitor {
-        // num_counters always has at least the `ZERO` counter.
-        info: CoverageInfo { num_counters: 1, num_expressions: 0 },
-        add_missing_operands: false,
-    };
-
-    coverage_visitor.visit_body(mir_body);
-
-    coverage_visitor.add_missing_operands = true;
-    coverage_visitor.visit_body(mir_body);
-
-    coverage_visitor.info
-}
-
-fn covered_file_name<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Option<Symbol> {
-    if tcx.is_mir_available(def_id) {
-        let body = mir_body(tcx, def_id);
-        for bb_data in body.basic_blocks().iter() {
-            for statement in bb_data.statements.iter() {
-                if let StatementKind::Coverage(box ref coverage) = statement.kind {
-                    if let Some(code_region) = coverage.code_region.as_ref() {
-                        if is_inlined(body, statement) {
-                            continue;
-                        }
-                        return Some(code_region.file_name);
-                    }
-                }
-            }
-        }
-    }
-    return None;
-}
-
-fn covered_code_regions<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> Vec<&'tcx CodeRegion> {
-    let body = mir_body(tcx, def_id);
-    body.basic_blocks()
-        .iter()
-        .map(|data| {
-            data.statements.iter().filter_map(|statement| match statement.kind {
-                StatementKind::Coverage(box ref coverage) => {
-                    if is_inlined(body, statement) {
-                        None
-                    } else {
-                        coverage.code_region.as_ref() // may be None
-                    }
-                }
-                _ => None,
-            })
-        })
-        .flatten()
-        .collect()
-}
-
-fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
-    let scope_data = &body.source_scopes[statement.source_info.scope];
-    scope_data.inlined.is_some() || scope_data.inlined_parent_scope.is_some()
-}
-
-/// This function ensures we obtain the correct MIR for the given item irrespective of
-/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
-/// mir.
-fn mir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx mir::Body<'tcx> {
-    let id = ty::WithOptConstParam::unknown(def_id);
-    let def = ty::InstanceDef::Item(id);
-    tcx.instance_mir(def)
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/spans.rs b/compiler/rustc_mir/src/transform/coverage/spans.rs
deleted file mode 100644
index 08cc87ccc34..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/spans.rs
+++ /dev/null
@@ -1,900 +0,0 @@
-use super::debug::term_type;
-use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
-
-use crate::util::spanview::source_range_no_file;
-
-use rustc_data_structures::graph::WithNumNodes;
-use rustc_middle::mir::{
-    self, AggregateKind, BasicBlock, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
-    TerminatorKind,
-};
-use rustc_middle::ty::TyCtxt;
-
-use rustc_span::source_map::original_sp;
-use rustc_span::{BytePos, ExpnKind, MacroKind, Span, Symbol};
-
-use std::cell::RefCell;
-use std::cmp::Ordering;
-
-#[derive(Debug, Copy, Clone)]
-pub(super) enum CoverageStatement {
-    Statement(BasicBlock, Span, usize),
-    Terminator(BasicBlock, Span),
-}
-
-impl CoverageStatement {
-    pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
-        match *self {
-            Self::Statement(bb, span, stmt_index) => {
-                let stmt = &mir_body[bb].statements[stmt_index];
-                format!(
-                    "{}: @{}[{}]: {:?}",
-                    source_range_no_file(tcx, &span),
-                    bb.index(),
-                    stmt_index,
-                    stmt
-                )
-            }
-            Self::Terminator(bb, span) => {
-                let term = mir_body[bb].terminator();
-                format!(
-                    "{}: @{}.{}: {:?}",
-                    source_range_no_file(tcx, &span),
-                    bb.index(),
-                    term_type(&term.kind),
-                    term.kind
-                )
-            }
-        }
-    }
-
-    pub fn span(&self) -> &Span {
-        match self {
-            Self::Statement(_, span, _) | Self::Terminator(_, span) => span,
-        }
-    }
-}
-
-/// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that
-/// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s.
-/// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent
-/// transforms can combine adjacent `Span`s and `CoverageSpan` from the same BCB, merging the
-/// `CoverageStatement` vectors, and the `Span`s to cover the extent of the combined `Span`s.
-///
-/// Note: A `CoverageStatement` merged into another CoverageSpan may come from a `BasicBlock` that
-/// is not part of the `CoverageSpan` bcb if the statement was included because it's `Span` matches
-/// or is subsumed by the `Span` associated with this `CoverageSpan`, and it's `BasicBlock`
-/// `is_dominated_by()` the `BasicBlock`s in this `CoverageSpan`.
-#[derive(Debug, Clone)]
-pub(super) struct CoverageSpan {
-    pub span: Span,
-    pub expn_span: Span,
-    pub current_macro_or_none: RefCell<Option<Option<Symbol>>>,
-    pub bcb: BasicCoverageBlock,
-    pub coverage_statements: Vec<CoverageStatement>,
-    pub is_closure: bool,
-}
-
-impl CoverageSpan {
-    pub fn for_fn_sig(fn_sig_span: Span) -> Self {
-        Self {
-            span: fn_sig_span,
-            expn_span: fn_sig_span,
-            current_macro_or_none: Default::default(),
-            bcb: START_BCB,
-            coverage_statements: vec![],
-            is_closure: false,
-        }
-    }
-
-    pub fn for_statement(
-        statement: &Statement<'tcx>,
-        span: Span,
-        expn_span: Span,
-        bcb: BasicCoverageBlock,
-        bb: BasicBlock,
-        stmt_index: usize,
-    ) -> Self {
-        let is_closure = match statement.kind {
-            StatementKind::Assign(box (_, Rvalue::Aggregate(box ref kind, _))) => match kind {
-                AggregateKind::Closure(_, _) | AggregateKind::Generator(_, _, _) => true,
-                _ => false,
-            },
-            _ => false,
-        };
-
-        Self {
-            span,
-            expn_span,
-            current_macro_or_none: Default::default(),
-            bcb,
-            coverage_statements: vec![CoverageStatement::Statement(bb, span, stmt_index)],
-            is_closure,
-        }
-    }
-
-    pub fn for_terminator(
-        span: Span,
-        expn_span: Span,
-        bcb: BasicCoverageBlock,
-        bb: BasicBlock,
-    ) -> Self {
-        Self {
-            span,
-            expn_span,
-            current_macro_or_none: Default::default(),
-            bcb,
-            coverage_statements: vec![CoverageStatement::Terminator(bb, span)],
-            is_closure: false,
-        }
-    }
-
-    pub fn merge_from(&mut self, mut other: CoverageSpan) {
-        debug_assert!(self.is_mergeable(&other));
-        self.span = self.span.to(other.span);
-        self.coverage_statements.append(&mut other.coverage_statements);
-    }
-
-    pub fn cutoff_statements_at(&mut self, cutoff_pos: BytePos) {
-        self.coverage_statements.retain(|covstmt| covstmt.span().hi() <= cutoff_pos);
-        if let Some(highest_covstmt) =
-            self.coverage_statements.iter().max_by_key(|covstmt| covstmt.span().hi())
-        {
-            self.span = self.span.with_hi(highest_covstmt.span().hi());
-        }
-    }
-
-    #[inline]
-    pub fn is_mergeable(&self, other: &Self) -> bool {
-        self.is_in_same_bcb(other) && !(self.is_closure || other.is_closure)
-    }
-
-    #[inline]
-    pub fn is_in_same_bcb(&self, other: &Self) -> bool {
-        self.bcb == other.bcb
-    }
-
-    pub fn format(&self, tcx: TyCtxt<'tcx>, mir_body: &'a mir::Body<'tcx>) -> String {
-        format!(
-            "{}\n    {}",
-            source_range_no_file(tcx, &self.span),
-            self.format_coverage_statements(tcx, mir_body).replace("\n", "\n    "),
-        )
-    }
-
-    pub fn format_coverage_statements(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        mir_body: &'a mir::Body<'tcx>,
-    ) -> String {
-        let mut sorted_coverage_statements = self.coverage_statements.clone();
-        sorted_coverage_statements.sort_unstable_by_key(|covstmt| match *covstmt {
-            CoverageStatement::Statement(bb, _, index) => (bb, index),
-            CoverageStatement::Terminator(bb, _) => (bb, usize::MAX),
-        });
-        sorted_coverage_statements
-            .iter()
-            .map(|covstmt| covstmt.format(tcx, mir_body))
-            .collect::<Vec<_>>()
-            .join("\n")
-    }
-
-    /// If the span is part of a macro, returns the macro name symbol.
-    pub fn current_macro(&self) -> Option<Symbol> {
-        self.current_macro_or_none
-            .borrow_mut()
-            .get_or_insert_with(|| {
-                if let ExpnKind::Macro(MacroKind::Bang, current_macro) =
-                    self.expn_span.ctxt().outer_expn_data().kind
-                {
-                    return Some(current_macro);
-                }
-                None
-            })
-            .map(|symbol| symbol)
-    }
-
-    /// If the span is part of a macro, and the macro is visible (expands directly to the given
-    /// body_span), returns the macro name symbol.
-    pub fn visible_macro(&self, body_span: Span) -> Option<Symbol> {
-        if let Some(current_macro) = self.current_macro() {
-            if self.expn_span.parent().unwrap_or_else(|| bug!("macro must have a parent")).ctxt()
-                == body_span.ctxt()
-            {
-                return Some(current_macro);
-            }
-        }
-        None
-    }
-
-    pub fn is_macro_expansion(&self) -> bool {
-        self.current_macro().is_some()
-    }
-}
-
-/// Converts the initial set of `CoverageSpan`s (one per MIR `Statement` or `Terminator`) into a
-/// minimal set of `CoverageSpan`s, using the BCB CFG to determine where it is safe and useful to:
-///
-///  * Remove duplicate source code coverage regions
-///  * Merge spans that represent continuous (both in source code and control flow), non-branching
-///    execution
-///  * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures)
-pub struct CoverageSpans<'a, 'tcx> {
-    /// The MIR, used to look up `BasicBlockData`.
-    mir_body: &'a mir::Body<'tcx>,
-
-    /// A `Span` covering the signature of function for the MIR.
-    fn_sig_span: Span,
-
-    /// A `Span` covering the function body of the MIR (typically from left curly brace to right
-    /// curly brace).
-    body_span: Span,
-
-    /// The BasicCoverageBlock Control Flow Graph (BCB CFG).
-    basic_coverage_blocks: &'a CoverageGraph,
-
-    /// The initial set of `CoverageSpan`s, sorted by `Span` (`lo` and `hi`) and by relative
-    /// dominance between the `BasicCoverageBlock`s of equal `Span`s.
-    sorted_spans_iter: Option<std::vec::IntoIter<CoverageSpan>>,
-
-    /// The current `CoverageSpan` to compare to its `prev`, to possibly merge, discard, force the
-    /// discard of the `prev` (and or `pending_dups`), or keep both (with `prev` moved to
-    /// `pending_dups`). If `curr` is not discarded or merged, it becomes `prev` for the next
-    /// iteration.
-    some_curr: Option<CoverageSpan>,
-
-    /// The original `span` for `curr`, in case `curr.span()` is modified. The `curr_original_span`
-    /// **must not be mutated** (except when advancing to the next `curr`), even if `curr.span()`
-    /// is mutated.
-    curr_original_span: Span,
-
-    /// The CoverageSpan from a prior iteration; typically assigned from that iteration's `curr`.
-    /// If that `curr` was discarded, `prev` retains its value from the previous iteration.
-    some_prev: Option<CoverageSpan>,
-
-    /// Assigned from `curr_original_span` from the previous iteration. The `prev_original_span`
-    /// **must not be mutated** (except when advancing to the next `prev`), even if `prev.span()`
-    /// is mutated.
-    prev_original_span: Span,
-
-    /// A copy of the expn_span from the prior iteration.
-    prev_expn_span: Option<Span>,
-
-    /// One or more `CoverageSpan`s with the same `Span` but different `BasicCoverageBlock`s, and
-    /// no `BasicCoverageBlock` in this list dominates another `BasicCoverageBlock` in the list.
-    /// If a new `curr` span also fits this criteria (compared to an existing list of
-    /// `pending_dups`), that `curr` `CoverageSpan` moves to `prev` before possibly being added to
-    /// the `pending_dups` list, on the next iteration. As a result, if `prev` and `pending_dups`
-    /// have the same `Span`, the criteria for `pending_dups` holds for `prev` as well: a `prev`
-    /// with a matching `Span` does not dominate any `pending_dup` and no `pending_dup` dominates a
-    /// `prev` with a matching `Span`)
-    pending_dups: Vec<CoverageSpan>,
-
-    /// The final `CoverageSpan`s to add to the coverage map. A `Counter` or `Expression`
-    /// will also be injected into the MIR for each `CoverageSpan`.
-    refined_spans: Vec<CoverageSpan>,
-}
-
-impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
-    /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be
-    /// counted.
-    ///
-    /// The basic steps are:
-    ///
-    /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each
-    ///    `BasicCoverageBlockData`.
-    /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position
-    ///    are sorted with longer spans before shorter spans; and equal spans are sorted
-    ///    (deterministically) based on "dominator" relationship (if any).
-    /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance,
-    ///    if another span or spans are already counting the same code region), or should be merged
-    ///    into a broader combined span (because it represents a contiguous, non-branching, and
-    ///    uninterrupted region of source code).
-    ///
-    ///    Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since
-    ///    closures have their own MIR, their `Span` in their enclosing function should be left
-    ///    "uncovered".
-    ///
-    /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need
-    /// to be).
-    pub(super) fn generate_coverage_spans(
-        mir_body: &'a mir::Body<'tcx>,
-        fn_sig_span: Span, // Ensured to be same SourceFile and SyntaxContext as `body_span`
-        body_span: Span,
-        basic_coverage_blocks: &'a CoverageGraph,
-    ) -> Vec<CoverageSpan> {
-        let mut coverage_spans = CoverageSpans {
-            mir_body,
-            fn_sig_span,
-            body_span,
-            basic_coverage_blocks,
-            sorted_spans_iter: None,
-            refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2),
-            some_curr: None,
-            curr_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
-            some_prev: None,
-            prev_original_span: Span::with_root_ctxt(BytePos(0), BytePos(0)),
-            prev_expn_span: None,
-            pending_dups: Vec::new(),
-        };
-
-        let sorted_spans = coverage_spans.mir_to_initial_sorted_coverage_spans();
-
-        coverage_spans.sorted_spans_iter = Some(sorted_spans.into_iter());
-
-        coverage_spans.to_refined_spans()
-    }
-
-    fn mir_to_initial_sorted_coverage_spans(&self) -> Vec<CoverageSpan> {
-        let mut initial_spans = Vec::<CoverageSpan>::with_capacity(self.mir_body.num_nodes() * 2);
-        for (bcb, bcb_data) in self.basic_coverage_blocks.iter_enumerated() {
-            for coverage_span in self.bcb_to_initial_coverage_spans(bcb, bcb_data) {
-                initial_spans.push(coverage_span);
-            }
-        }
-
-        if initial_spans.is_empty() {
-            // This can happen if, for example, the function is unreachable (contains only a
-            // `BasicBlock`(s) with an `Unreachable` terminator).
-            return initial_spans;
-        }
-
-        initial_spans.push(CoverageSpan::for_fn_sig(self.fn_sig_span));
-
-        initial_spans.sort_unstable_by(|a, b| {
-            if a.span.lo() == b.span.lo() {
-                if a.span.hi() == b.span.hi() {
-                    if a.is_in_same_bcb(b) {
-                        Some(Ordering::Equal)
-                    } else {
-                        // Sort equal spans by dominator relationship, in reverse order (so
-                        // dominators always come after the dominated equal spans). When later
-                        // comparing two spans in order, the first will either dominate the second,
-                        // or they will have no dominator relationship.
-                        self.basic_coverage_blocks.dominators().rank_partial_cmp(b.bcb, a.bcb)
-                    }
-                } else {
-                    // Sort hi() in reverse order so shorter spans are attempted after longer spans.
-                    // This guarantees that, if a `prev` span overlaps, and is not equal to, a
-                    // `curr` span, the prev span either extends further left of the curr span, or
-                    // they start at the same position and the prev span extends further right of
-                    // the end of the curr span.
-                    b.span.hi().partial_cmp(&a.span.hi())
-                }
-            } else {
-                a.span.lo().partial_cmp(&b.span.lo())
-            }
-            .unwrap()
-        });
-
-        initial_spans
-    }
-
-    /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and
-    /// de-duplicated `CoverageSpan`s.
-    fn to_refined_spans(mut self) -> Vec<CoverageSpan> {
-        while self.next_coverage_span() {
-            if self.some_prev.is_none() {
-                debug!("  initial span");
-                self.check_invoked_macro_name_span();
-            } else if self.curr().is_mergeable(self.prev()) {
-                debug!("  same bcb (and neither is a closure), merge with prev={:?}", self.prev());
-                let prev = self.take_prev();
-                self.curr_mut().merge_from(prev);
-                self.check_invoked_macro_name_span();
-            // Note that curr.span may now differ from curr_original_span
-            } else if self.prev_ends_before_curr() {
-                debug!(
-                    "  different bcbs and disjoint spans, so keep curr for next iter, and add \
-                    prev={:?}",
-                    self.prev()
-                );
-                let prev = self.take_prev();
-                self.push_refined_span(prev);
-                self.check_invoked_macro_name_span();
-            } else if self.prev().is_closure {
-                // drop any equal or overlapping span (`curr`) and keep `prev` to test again in the
-                // next iter
-                debug!(
-                    "  curr overlaps a closure (prev). Drop curr and keep prev for next iter. \
-                    prev={:?}",
-                    self.prev()
-                );
-                self.take_curr();
-            } else if self.curr().is_closure {
-                self.carve_out_span_for_closure();
-            } else if self.prev_original_span == self.curr().span {
-                // Note that this compares the new (`curr`) span to `prev_original_span`.
-                // In this branch, the actual span byte range of `prev_original_span` is not
-                // important. What is important is knowing whether the new `curr` span was
-                // **originally** the same as the original span of `prev()`. The original spans
-                // reflect their original sort order, and for equal spans, conveys a partial
-                // ordering based on CFG dominator priority.
-                if self.prev().is_macro_expansion() && self.curr().is_macro_expansion() {
-                    // Macros that expand to include branching (such as
-                    // `assert_eq!()`, `assert_ne!()`, `info!()`, `debug!()`, or
-                    // `trace!()) typically generate callee spans with identical
-                    // ranges (typically the full span of the macro) for all
-                    // `BasicBlocks`. This makes it impossible to distinguish
-                    // the condition (`if val1 != val2`) from the optional
-                    // branched statements (such as the call to `panic!()` on
-                    // assert failure). In this case it is better (or less
-                    // worse) to drop the optional branch bcbs and keep the
-                    // non-conditional statements, to count when reached.
-                    debug!(
-                        "  curr and prev are part of a macro expansion, and curr has the same span \
-                        as prev, but is in a different bcb. Drop curr and keep prev for next iter. \
-                        prev={:?}",
-                        self.prev()
-                    );
-                    self.take_curr();
-                } else {
-                    self.hold_pending_dups_unless_dominated();
-                }
-            } else {
-                self.cutoff_prev_at_overlapping_curr();
-                self.check_invoked_macro_name_span();
-            }
-        }
-
-        debug!("    AT END, adding last prev={:?}", self.prev());
-        let prev = self.take_prev();
-        let pending_dups = self.pending_dups.split_off(0);
-        for dup in pending_dups {
-            debug!("    ...adding at least one pending dup={:?}", dup);
-            self.push_refined_span(dup);
-        }
-
-        // Async functions wrap a closure that implements the body to be executed. The enclosing
-        // function is called and returns an `impl Future` without initially executing any of the
-        // body. To avoid showing the return from the enclosing function as a "covered" return from
-        // the closure, the enclosing function's `TerminatorKind::Return`s `CoverageSpan` is
-        // excluded. The closure's `Return` is the only one that will be counted. This provides
-        // adequate coverage, and more intuitive counts. (Avoids double-counting the closing brace
-        // of the function body.)
-        let body_ends_with_closure = if let Some(last_covspan) = self.refined_spans.last() {
-            last_covspan.is_closure && last_covspan.span.hi() == self.body_span.hi()
-        } else {
-            false
-        };
-
-        if !body_ends_with_closure {
-            self.push_refined_span(prev);
-        }
-
-        // Remove `CoverageSpan`s derived from closures, originally added to ensure the coverage
-        // regions for the current function leave room for the closure's own coverage regions
-        // (injected separately, from the closure's own MIR).
-        self.refined_spans.retain(|covspan| !covspan.is_closure);
-        self.refined_spans
-    }
-
-    fn push_refined_span(&mut self, covspan: CoverageSpan) {
-        let len = self.refined_spans.len();
-        if len > 0 {
-            let last = &mut self.refined_spans[len - 1];
-            if last.is_mergeable(&covspan) {
-                debug!(
-                    "merging new refined span with last refined span, last={:?}, covspan={:?}",
-                    last, covspan
-                );
-                last.merge_from(covspan);
-                return;
-            }
-        }
-        self.refined_spans.push(covspan)
-    }
-
-    fn check_invoked_macro_name_span(&mut self) {
-        if let Some(visible_macro) = self.curr().visible_macro(self.body_span) {
-            if self.prev_expn_span.map_or(true, |prev_expn_span| {
-                self.curr().expn_span.ctxt() != prev_expn_span.ctxt()
-            }) {
-                let merged_prefix_len = self.curr_original_span.lo() - self.curr().span.lo();
-                let after_macro_bang =
-                    merged_prefix_len + BytePos(visible_macro.as_str().bytes().count() as u32 + 1);
-                let mut macro_name_cov = self.curr().clone();
-                self.curr_mut().span =
-                    self.curr().span.with_lo(self.curr().span.lo() + after_macro_bang);
-                macro_name_cov.span =
-                    macro_name_cov.span.with_hi(macro_name_cov.span.lo() + after_macro_bang);
-                debug!(
-                    "  and curr starts a new macro expansion, so add a new span just for \
-                            the macro `{}!`, new span={:?}",
-                    visible_macro, macro_name_cov
-                );
-                self.push_refined_span(macro_name_cov);
-            }
-        }
-    }
-
-    // Generate a set of `CoverageSpan`s from the filtered set of `Statement`s and `Terminator`s of
-    // the `BasicBlock`(s) in the given `BasicCoverageBlockData`. One `CoverageSpan` is generated
-    // for each `Statement` and `Terminator`. (Note that subsequent stages of coverage analysis will
-    // merge some `CoverageSpan`s, at which point a `CoverageSpan` may represent multiple
-    // `Statement`s and/or `Terminator`s.)
-    fn bcb_to_initial_coverage_spans(
-        &self,
-        bcb: BasicCoverageBlock,
-        bcb_data: &'a BasicCoverageBlockData,
-    ) -> Vec<CoverageSpan> {
-        bcb_data
-            .basic_blocks
-            .iter()
-            .flat_map(|&bb| {
-                let data = &self.mir_body[bb];
-                data.statements
-                    .iter()
-                    .enumerate()
-                    .filter_map(move |(index, statement)| {
-                        filtered_statement_span(statement).map(|span| {
-                            CoverageSpan::for_statement(
-                                statement,
-                                function_source_span(span, self.body_span),
-                                span,
-                                bcb,
-                                bb,
-                                index,
-                            )
-                        })
-                    })
-                    .chain(filtered_terminator_span(data.terminator()).map(|span| {
-                        CoverageSpan::for_terminator(
-                            function_source_span(span, self.body_span),
-                            span,
-                            bcb,
-                            bb,
-                        )
-                    }))
-            })
-            .collect()
-    }
-
-    fn curr(&self) -> &CoverageSpan {
-        self.some_curr
-            .as_ref()
-            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
-    }
-
-    fn curr_mut(&mut self) -> &mut CoverageSpan {
-        self.some_curr
-            .as_mut()
-            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
-    }
-
-    fn prev(&self) -> &CoverageSpan {
-        self.some_prev
-            .as_ref()
-            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
-    }
-
-    fn prev_mut(&mut self) -> &mut CoverageSpan {
-        self.some_prev
-            .as_mut()
-            .unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
-    }
-
-    fn take_prev(&mut self) -> CoverageSpan {
-        self.some_prev.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_prev"))
-    }
-
-    /// If there are `pending_dups` but `prev` is not a matching dup (`prev.span` doesn't match the
-    /// `pending_dups` spans), then one of the following two things happened during the previous
-    /// iteration:
-    ///   * the previous `curr` span (which is now `prev`) was not a duplicate of the pending_dups
-    ///     (in which case there should be at least two spans in `pending_dups`); or
-    ///   * the `span` of `prev` was modified by `curr_mut().merge_from(prev)` (in which case
-    ///     `pending_dups` could have as few as one span)
-    /// In either case, no more spans will match the span of `pending_dups`, so
-    /// add the `pending_dups` if they don't overlap `curr`, and clear the list.
-    fn check_pending_dups(&mut self) {
-        if let Some(dup) = self.pending_dups.last() {
-            if dup.span != self.prev().span {
-                debug!(
-                    "    SAME spans, but pending_dups are NOT THE SAME, so BCBs matched on \
-                    previous iteration, or prev started a new disjoint span"
-                );
-                if dup.span.hi() <= self.curr().span.lo() {
-                    let pending_dups = self.pending_dups.split_off(0);
-                    for dup in pending_dups.into_iter() {
-                        debug!("    ...adding at least one pending={:?}", dup);
-                        self.push_refined_span(dup);
-                    }
-                } else {
-                    self.pending_dups.clear();
-                }
-            }
-        }
-    }
-
-    /// Advance `prev` to `curr` (if any), and `curr` to the next `CoverageSpan` in sorted order.
-    fn next_coverage_span(&mut self) -> bool {
-        if let Some(curr) = self.some_curr.take() {
-            self.prev_expn_span = Some(curr.expn_span);
-            self.some_prev = Some(curr);
-            self.prev_original_span = self.curr_original_span;
-        }
-        while let Some(curr) = self.sorted_spans_iter.as_mut().unwrap().next() {
-            debug!("FOR curr={:?}", curr);
-            if self.some_prev.is_some() && self.prev_starts_after_next(&curr) {
-                debug!(
-                    "  prev.span starts after curr.span, so curr will be dropped (skipping past \
-                    closure?); prev={:?}",
-                    self.prev()
-                );
-            } else {
-                // Save a copy of the original span for `curr` in case the `CoverageSpan` is changed
-                // by `self.curr_mut().merge_from(prev)`.
-                self.curr_original_span = curr.span;
-                self.some_curr.replace(curr);
-                self.check_pending_dups();
-                return true;
-            }
-        }
-        false
-    }
-
-    /// If called, then the next call to `next_coverage_span()` will *not* update `prev` with the
-    /// `curr` coverage span.
-    fn take_curr(&mut self) -> CoverageSpan {
-        self.some_curr.take().unwrap_or_else(|| bug!("invalid attempt to unwrap a None some_curr"))
-    }
-
-    /// Returns true if the curr span should be skipped because prev has already advanced beyond the
-    /// end of curr. This can only happen if a prior iteration updated `prev` to skip past a region
-    /// of code, such as skipping past a closure.
-    fn prev_starts_after_next(&self, next_curr: &CoverageSpan) -> bool {
-        self.prev().span.lo() > next_curr.span.lo()
-    }
-
-    /// Returns true if the curr span starts past the end of the prev span, which means they don't
-    /// overlap, so we now know the prev can be added to the refined coverage spans.
-    fn prev_ends_before_curr(&self) -> bool {
-        self.prev().span.hi() <= self.curr().span.lo()
-    }
-
-    /// If `prev`s span extends left of the closure (`curr`), carve out the closure's span from
-    /// `prev`'s span. (The closure's coverage counters will be injected when processing the
-    /// closure's own MIR.) Add the portion of the span to the left of the closure; and if the span
-    /// extends to the right of the closure, update `prev` to that portion of the span. For any
-    /// `pending_dups`, repeat the same process.
-    fn carve_out_span_for_closure(&mut self) {
-        let curr_span = self.curr().span;
-        let left_cutoff = curr_span.lo();
-        let right_cutoff = curr_span.hi();
-        let has_pre_closure_span = self.prev().span.lo() < right_cutoff;
-        let has_post_closure_span = self.prev().span.hi() > right_cutoff;
-        let mut pending_dups = self.pending_dups.split_off(0);
-        if has_pre_closure_span {
-            let mut pre_closure = self.prev().clone();
-            pre_closure.span = pre_closure.span.with_hi(left_cutoff);
-            debug!("  prev overlaps a closure. Adding span for pre_closure={:?}", pre_closure);
-            if !pending_dups.is_empty() {
-                for mut dup in pending_dups.iter().cloned() {
-                    dup.span = dup.span.with_hi(left_cutoff);
-                    debug!("    ...and at least one pre_closure dup={:?}", dup);
-                    self.push_refined_span(dup);
-                }
-            }
-            self.push_refined_span(pre_closure);
-        }
-        if has_post_closure_span {
-            // Mutate `prev.span()` to start after the closure (and discard curr).
-            // (**NEVER** update `prev_original_span` because it affects the assumptions
-            // about how the `CoverageSpan`s are ordered.)
-            self.prev_mut().span = self.prev().span.with_lo(right_cutoff);
-            debug!("  Mutated prev.span to start after the closure. prev={:?}", self.prev());
-            for dup in pending_dups.iter_mut() {
-                debug!("    ...and at least one overlapping dup={:?}", dup);
-                dup.span = dup.span.with_lo(right_cutoff);
-            }
-            self.pending_dups.append(&mut pending_dups);
-            let closure_covspan = self.take_curr();
-            self.push_refined_span(closure_covspan); // since self.prev() was already updated
-        } else {
-            pending_dups.clear();
-        }
-    }
-
-    /// Called if `curr.span` equals `prev_original_span` (and potentially equal to all
-    /// `pending_dups` spans, if any). Keep in mind, `prev.span()` may have been changed.
-    /// If prev.span() was merged into other spans (with matching BCB, for instance),
-    /// `prev.span.hi()` will be greater than (further right of) `prev_original_span.hi()`.
-    /// If prev.span() was split off to the right of a closure, prev.span().lo() will be
-    /// greater than prev_original_span.lo(). The actual span of `prev_original_span` is
-    /// not as important as knowing that `prev()` **used to have the same span** as `curr(),
-    /// which means their sort order is still meaningful for determinating the dominator
-    /// relationship.
-    ///
-    /// When two `CoverageSpan`s have the same `Span`, dominated spans can be discarded; but if
-    /// neither `CoverageSpan` dominates the other, both (or possibly more than two) are held,
-    /// until their disposition is determined. In this latter case, the `prev` dup is moved into
-    /// `pending_dups` so the new `curr` dup can be moved to `prev` for the next iteration.
-    fn hold_pending_dups_unless_dominated(&mut self) {
-        // Equal coverage spans are ordered by dominators before dominated (if any), so it should be
-        // impossible for `curr` to dominate any previous `CoverageSpan`.
-        debug_assert!(!self.span_bcb_is_dominated_by(self.prev(), self.curr()));
-
-        let initial_pending_count = self.pending_dups.len();
-        if initial_pending_count > 0 {
-            let mut pending_dups = self.pending_dups.split_off(0);
-            pending_dups.retain(|dup| !self.span_bcb_is_dominated_by(self.curr(), dup));
-            self.pending_dups.append(&mut pending_dups);
-            if self.pending_dups.len() < initial_pending_count {
-                debug!(
-                    "  discarded {} of {} pending_dups that dominated curr",
-                    initial_pending_count - self.pending_dups.len(),
-                    initial_pending_count
-                );
-            }
-        }
-
-        if self.span_bcb_is_dominated_by(self.curr(), self.prev()) {
-            debug!(
-                "  different bcbs but SAME spans, and prev dominates curr. Discard prev={:?}",
-                self.prev()
-            );
-            self.cutoff_prev_at_overlapping_curr();
-        // If one span dominates the other, assocate the span with the code from the dominated
-        // block only (`curr`), and discard the overlapping portion of the `prev` span. (Note
-        // that if `prev.span` is wider than `prev_original_span`, a `CoverageSpan` will still
-        // be created for `prev`s block, for the non-overlapping portion, left of `curr.span`.)
-        //
-        // For example:
-        //     match somenum {
-        //         x if x < 1 => { ... }
-        //     }...
-        //
-        // The span for the first `x` is referenced by both the pattern block (every time it is
-        // evaluated) and the arm code (only when matched). The counter will be applied only to
-        // the dominated block. This allows coverage to track and highlight things like the
-        // assignment of `x` above, if the branch is matched, making `x` available to the arm
-        // code; and to track and highlight the question mark `?` "try" operator at the end of
-        // a function call returning a `Result`, so the `?` is covered when the function returns
-        // an `Err`, and not counted as covered if the function always returns `Ok`.
-        } else {
-            // Save `prev` in `pending_dups`. (`curr` will become `prev` in the next iteration.)
-            // If the `curr` CoverageSpan is later discarded, `pending_dups` can be discarded as
-            // well; but if `curr` is added to refined_spans, the `pending_dups` will also be added.
-            debug!(
-                "  different bcbs but SAME spans, and neither dominates, so keep curr for \
-                next iter, and, pending upcoming spans (unless overlapping) add prev={:?}",
-                self.prev()
-            );
-            let prev = self.take_prev();
-            self.pending_dups.push(prev);
-        }
-    }
-
-    /// `curr` overlaps `prev`. If `prev`s span extends left of `curr`s span, keep _only_
-    /// statements that end before `curr.lo()` (if any), and add the portion of the
-    /// combined span for those statements. Any other statements have overlapping spans
-    /// that can be ignored because `curr` and/or other upcoming statements/spans inside
-    /// the overlap area will produce their own counters. This disambiguation process
-    /// avoids injecting multiple counters for overlapping spans, and the potential for
-    /// double-counting.
-    fn cutoff_prev_at_overlapping_curr(&mut self) {
-        debug!(
-            "  different bcbs, overlapping spans, so ignore/drop pending and only add prev \
-            if it has statements that end before curr; prev={:?}",
-            self.prev()
-        );
-        if self.pending_dups.is_empty() {
-            let curr_span = self.curr().span;
-            self.prev_mut().cutoff_statements_at(curr_span.lo());
-            if self.prev().coverage_statements.is_empty() {
-                debug!("  ... no non-overlapping statements to add");
-            } else {
-                debug!("  ... adding modified prev={:?}", self.prev());
-                let prev = self.take_prev();
-                self.push_refined_span(prev);
-            }
-        } else {
-            // with `pending_dups`, `prev` cannot have any statements that don't overlap
-            self.pending_dups.clear();
-        }
-    }
-
-    fn span_bcb_is_dominated_by(&self, covspan: &CoverageSpan, dom_covspan: &CoverageSpan) -> bool {
-        self.basic_coverage_blocks.is_dominated_by(covspan.bcb, dom_covspan.bcb)
-    }
-}
-
-/// If the MIR `Statement` has a span contributive to computing coverage spans,
-/// return it; otherwise return `None`.
-pub(super) fn filtered_statement_span(statement: &'a Statement<'tcx>) -> Option<Span> {
-    match statement.kind {
-        // These statements have spans that are often outside the scope of the executed source code
-        // for their parent `BasicBlock`.
-        StatementKind::StorageLive(_)
-        | StatementKind::StorageDead(_)
-        // Coverage should not be encountered, but don't inject coverage coverage
-        | StatementKind::Coverage(_)
-        // Ignore `Nop`s
-        | StatementKind::Nop => None,
-
-        // FIXME(#78546): MIR InstrumentCoverage - Can the source_info.span for `FakeRead`
-        // statements be more consistent?
-        //
-        // FakeReadCause::ForGuardBinding, in this example:
-        //     match somenum {
-        //         x if x < 1 => { ... }
-        //     }...
-        // The BasicBlock within the match arm code included one of these statements, but the span
-        // for it covered the `1` in this source. The actual statements have nothing to do with that
-        // source span:
-        //     FakeRead(ForGuardBinding, _4);
-        // where `_4` is:
-        //     _4 = &_1; (at the span for the first `x`)
-        // and `_1` is the `Place` for `somenum`.
-        //
-        // If and when the Issue is resolved, remove this special case match pattern:
-        StatementKind::FakeRead(box (cause, _)) if cause == FakeReadCause::ForGuardBinding => None,
-
-        // Retain spans from all other statements
-        StatementKind::FakeRead(box (_, _)) // Not including `ForGuardBinding`
-        | StatementKind::CopyNonOverlapping(..)
-        | StatementKind::Assign(_)
-        | StatementKind::SetDiscriminant { .. }
-        | StatementKind::LlvmInlineAsm(_)
-        | StatementKind::Retag(_, _)
-        | StatementKind::AscribeUserType(_, _) => {
-            Some(statement.source_info.span)
-        }
-    }
-}
-
-/// If the MIR `Terminator` has a span contributive to computing coverage spans,
-/// return it; otherwise return `None`.
-pub(super) fn filtered_terminator_span(terminator: &'a Terminator<'tcx>) -> Option<Span> {
-    match terminator.kind {
-        // These terminators have spans that don't positively contribute to computing a reasonable
-        // span of actually executed source code. (For example, SwitchInt terminators extracted from
-        // an `if condition { block }` has a span that includes the executed block, if true,
-        // but for coverage, the code region executed, up to *and* through the SwitchInt,
-        // actually stops before the if's block.)
-        TerminatorKind::Unreachable // Unreachable blocks are not connected to the MIR CFG
-        | TerminatorKind::Assert { .. }
-        | TerminatorKind::Drop { .. }
-        | TerminatorKind::DropAndReplace { .. }
-        | TerminatorKind::SwitchInt { .. }
-        // For `FalseEdge`, only the `real` branch is taken, so it is similar to a `Goto`.
-        | TerminatorKind::FalseEdge { .. }
-        | TerminatorKind::Goto { .. } => None,
-
-        // Call `func` operand can have a more specific span when part of a chain of calls
-        | TerminatorKind::Call { ref func, .. } => {
-            let mut span = terminator.source_info.span;
-            if let mir::Operand::Constant(box constant) = func {
-                if constant.span.lo() > span.lo() {
-                    span = span.with_lo(constant.span.lo());
-                }
-            }
-            Some(span)
-        }
-
-        // Retain spans from all other terminators
-        TerminatorKind::Resume
-        | TerminatorKind::Abort
-        | TerminatorKind::Return
-        | TerminatorKind::Yield { .. }
-        | TerminatorKind::GeneratorDrop
-        | TerminatorKind::FalseUnwind { .. }
-        | TerminatorKind::InlineAsm { .. } => {
-            Some(terminator.source_info.span)
-        }
-    }
-}
-
-/// Returns an extrapolated span (pre-expansion[^1]) corresponding to a range
-/// within the function's body source. This span is guaranteed to be contained
-/// within, or equal to, the `body_span`. If the extrapolated span is not
-/// contained within the `body_span`, the `body_span` is returned.
-///
-/// [^1]Expansions result from Rust syntax including macros, syntactic sugar,
-/// etc.).
-#[inline]
-pub(super) fn function_source_span(span: Span, body_span: Span) -> Span {
-    let original_span = original_sp(span, body_span).with_ctxt(body_span.ctxt());
-    if body_span.contains(original_span) { original_span } else { body_span }
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml b/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
deleted file mode 100644
index cc93fd482b5..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/test_macros/Cargo.toml
+++ /dev/null
@@ -1,8 +0,0 @@
-[package]
-name = "coverage_test_macros"
-version = "0.0.0"
-edition = "2018"
-
-[lib]
-proc-macro = true
-doctest = false
diff --git a/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs b/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs
deleted file mode 100644
index 3d6095d2738..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/test_macros/src/lib.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-use proc_macro::TokenStream;
-
-#[proc_macro]
-pub fn let_bcb(item: TokenStream) -> TokenStream {
-    format!("let bcb{} = graph::BasicCoverageBlock::from_usize({});", item, item).parse().unwrap()
-}
diff --git a/compiler/rustc_mir/src/transform/coverage/tests.rs b/compiler/rustc_mir/src/transform/coverage/tests.rs
deleted file mode 100644
index 14dd0a8b924..00000000000
--- a/compiler/rustc_mir/src/transform/coverage/tests.rs
+++ /dev/null
@@ -1,721 +0,0 @@
-//! This crate hosts a selection of "unit tests" for components of the `InstrumentCoverage` MIR
-//! pass.
-//!
-//! ```shell
-//! ./x.py test --keep-stage 1 compiler/rustc_mir --test-args '--show-output coverage'
-//! ```
-//!
-//! The tests construct a few "mock" objects, as needed, to support the `InstrumentCoverage`
-//! functions and algorithms. Mocked objects include instances of `mir::Body`; including
-//! `Terminator`s of various `kind`s, and `Span` objects. Some functions used by or used on
-//! real, runtime versions of these mocked-up objects have constraints (such as cross-thread
-//! limitations) and deep dependencies on other elements of the full Rust compiler (which is
-//! *not* constructed or mocked for these tests).
-//!
-//! Of particular note, attempting to simply print elements of the `mir::Body` with default
-//! `Debug` formatting can fail because some `Debug` format implementations require the
-//! `TyCtxt`, obtained via a static global variable that is *not* set for these tests.
-//! Initializing the global type context is prohibitively complex for the scope and scale of these
-//! tests (essentially requiring initializing the entire compiler).
-//!
-//! Also note, some basic features of `Span` also rely on the `Span`s own "session globals", which
-//! are unrelated to the `TyCtxt` global. Without initializing the `Span` session globals, some
-//! basic, coverage-specific features would be impossible to test, but thankfully initializing these
-//! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument
-//! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`.
-
-use super::counters;
-use super::debug;
-use super::graph;
-use super::spans;
-
-use coverage_test_macros::let_bcb;
-
-use rustc_data_structures::graph::WithNumNodes;
-use rustc_data_structures::graph::WithSuccessors;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::coverage::CoverageKind;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, DebruijnIndex, TyS, TypeFlags};
-use rustc_span::{self, BytePos, Pos, Span, DUMMY_SP};
-
-// All `TEMP_BLOCK` targets should be replaced before calling `to_body() -> mir::Body`.
-const TEMP_BLOCK: BasicBlock = BasicBlock::MAX;
-
-fn dummy_ty() -> &'static TyS<'static> {
-    thread_local! {
-        static DUMMY_TYS: &'static TyS<'static> = Box::leak(Box::new(TyS::make_for_test(
-            ty::Bool,
-            TypeFlags::empty(),
-            DebruijnIndex::from_usize(0),
-        )));
-    }
-
-    &DUMMY_TYS.with(|tys| *tys)
-}
-
-struct MockBlocks<'tcx> {
-    blocks: IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    dummy_place: Place<'tcx>,
-    next_local: usize,
-}
-
-impl<'tcx> MockBlocks<'tcx> {
-    fn new() -> Self {
-        Self {
-            blocks: IndexVec::new(),
-            dummy_place: Place { local: RETURN_PLACE, projection: ty::List::empty() },
-            next_local: 0,
-        }
-    }
-
-    fn new_temp(&mut self) -> Local {
-        let index = self.next_local;
-        self.next_local += 1;
-        Local::new(index)
-    }
-
-    fn push(&mut self, kind: TerminatorKind<'tcx>) -> BasicBlock {
-        let next_lo = if let Some(last) = self.blocks.last() {
-            self.blocks[last].terminator().source_info.span.hi()
-        } else {
-            BytePos(1)
-        };
-        let next_hi = next_lo + BytePos(1);
-        self.blocks.push(BasicBlockData {
-            statements: vec![],
-            terminator: Some(Terminator {
-                source_info: SourceInfo::outermost(Span::with_root_ctxt(next_lo, next_hi)),
-                kind,
-            }),
-            is_cleanup: false,
-        })
-    }
-
-    fn link(&mut self, from_block: BasicBlock, to_block: BasicBlock) {
-        match self.blocks[from_block].terminator_mut().kind {
-            TerminatorKind::Assert { ref mut target, .. }
-            | TerminatorKind::Call { destination: Some((_, ref mut target)), .. }
-            | TerminatorKind::Drop { ref mut target, .. }
-            | TerminatorKind::DropAndReplace { ref mut target, .. }
-            | TerminatorKind::FalseEdge { real_target: ref mut target, .. }
-            | TerminatorKind::FalseUnwind { real_target: ref mut target, .. }
-            | TerminatorKind::Goto { ref mut target }
-            | TerminatorKind::InlineAsm { destination: Some(ref mut target), .. }
-            | TerminatorKind::Yield { resume: ref mut target, .. } => *target = to_block,
-            ref invalid => bug!("Invalid from_block: {:?}", invalid),
-        }
-    }
-
-    fn add_block_from(
-        &mut self,
-        some_from_block: Option<BasicBlock>,
-        to_kind: TerminatorKind<'tcx>,
-    ) -> BasicBlock {
-        let new_block = self.push(to_kind);
-        if let Some(from_block) = some_from_block {
-            self.link(from_block, new_block);
-        }
-        new_block
-    }
-
-    fn set_branch(&mut self, switchint: BasicBlock, branch_index: usize, to_block: BasicBlock) {
-        match self.blocks[switchint].terminator_mut().kind {
-            TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                let mut branches = targets.iter().collect::<Vec<_>>();
-                let otherwise = if branch_index == branches.len() {
-                    to_block
-                } else {
-                    let old_otherwise = targets.otherwise();
-                    if branch_index > branches.len() {
-                        branches.push((branches.len() as u128, old_otherwise));
-                        while branches.len() < branch_index {
-                            branches.push((branches.len() as u128, TEMP_BLOCK));
-                        }
-                        to_block
-                    } else {
-                        branches[branch_index] = (branch_index as u128, to_block);
-                        old_otherwise
-                    }
-                };
-                *targets = SwitchTargets::new(branches.into_iter(), otherwise);
-            }
-            ref invalid => bug!("Invalid BasicBlock kind or no to_block: {:?}", invalid),
-        }
-    }
-
-    fn call(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
-        self.add_block_from(
-            some_from_block,
-            TerminatorKind::Call {
-                func: Operand::Copy(self.dummy_place.clone()),
-                args: vec![],
-                destination: Some((self.dummy_place.clone(), TEMP_BLOCK)),
-                cleanup: None,
-                from_hir_call: false,
-                fn_span: DUMMY_SP,
-            },
-        )
-    }
-
-    fn goto(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
-        self.add_block_from(some_from_block, TerminatorKind::Goto { target: TEMP_BLOCK })
-    }
-
-    fn switchint(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
-        let switchint_kind = TerminatorKind::SwitchInt {
-            discr: Operand::Move(Place::from(self.new_temp())),
-            switch_ty: dummy_ty(),
-            targets: SwitchTargets::static_if(0, TEMP_BLOCK, TEMP_BLOCK),
-        };
-        self.add_block_from(some_from_block, switchint_kind)
-    }
-
-    fn return_(&mut self, some_from_block: Option<BasicBlock>) -> BasicBlock {
-        self.add_block_from(some_from_block, TerminatorKind::Return)
-    }
-
-    fn to_body(self) -> Body<'tcx> {
-        Body::new_cfg_only(self.blocks)
-    }
-}
-
-fn debug_basic_blocks(mir_body: &Body<'tcx>) -> String {
-    format!(
-        "{:?}",
-        mir_body
-            .basic_blocks()
-            .iter_enumerated()
-            .map(|(bb, data)| {
-                let term = &data.terminator();
-                let kind = &term.kind;
-                let span = term.source_info.span;
-                let sp = format!("(span:{},{})", span.lo().to_u32(), span.hi().to_u32());
-                match kind {
-                    TerminatorKind::Assert { target, .. }
-                    | TerminatorKind::Call { destination: Some((_, target)), .. }
-                    | TerminatorKind::Drop { target, .. }
-                    | TerminatorKind::DropAndReplace { target, .. }
-                    | TerminatorKind::FalseEdge { real_target: target, .. }
-                    | TerminatorKind::FalseUnwind { real_target: target, .. }
-                    | TerminatorKind::Goto { target }
-                    | TerminatorKind::InlineAsm { destination: Some(target), .. }
-                    | TerminatorKind::Yield { resume: target, .. } => {
-                        format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target)
-                    }
-                    TerminatorKind::SwitchInt { targets, .. } => {
-                        format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets)
-                    }
-                    _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)),
-                }
-            })
-            .collect::<Vec<_>>()
-    )
-}
-
-static PRINT_GRAPHS: bool = false;
-
-fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
-    if PRINT_GRAPHS {
-        println!(
-            "digraph {} {{\n{}\n}}",
-            name,
-            mir_body
-                .basic_blocks()
-                .iter_enumerated()
-                .map(|(bb, data)| {
-                    format!(
-                        "    {:?} [label=\"{:?}: {}\"];\n{}",
-                        bb,
-                        bb,
-                        debug::term_type(&data.terminator().kind),
-                        mir_body
-                            .successors(bb)
-                            .map(|successor| { format!("    {:?} -> {:?};", bb, successor) })
-                            .collect::<Vec<_>>()
-                            .join("\n")
-                    )
-                })
-                .collect::<Vec<_>>()
-                .join("\n")
-        );
-    }
-}
-
-fn print_coverage_graphviz(
-    name: &str,
-    mir_body: &Body<'_>,
-    basic_coverage_blocks: &graph::CoverageGraph,
-) {
-    if PRINT_GRAPHS {
-        println!(
-            "digraph {} {{\n{}\n}}",
-            name,
-            basic_coverage_blocks
-                .iter_enumerated()
-                .map(|(bcb, bcb_data)| {
-                    format!(
-                        "    {:?} [label=\"{:?}: {}\"];\n{}",
-                        bcb,
-                        bcb,
-                        debug::term_type(&bcb_data.terminator(mir_body).kind),
-                        basic_coverage_blocks
-                            .successors(bcb)
-                            .map(|successor| { format!("    {:?} -> {:?};", bcb, successor) })
-                            .collect::<Vec<_>>()
-                            .join("\n")
-                    )
-                })
-                .collect::<Vec<_>>()
-                .join("\n")
-        );
-    }
-}
-
-/// Create a mock `Body` with a simple flow.
-fn goto_switchint() -> Body<'a> {
-    let mut blocks = MockBlocks::new();
-    let start = blocks.call(None);
-    let goto = blocks.goto(Some(start));
-    let switchint = blocks.switchint(Some(goto));
-    let then_call = blocks.call(None);
-    let else_call = blocks.call(None);
-    blocks.set_branch(switchint, 0, then_call);
-    blocks.set_branch(switchint, 1, else_call);
-    blocks.return_(Some(then_call));
-    blocks.return_(Some(else_call));
-
-    let mir_body = blocks.to_body();
-    print_mir_graphviz("mir_goto_switchint", &mir_body);
-    /* Graphviz character plots created using: `graph-easy --as=boxart`:
-                        ┌────────────────┐
-                        │   bb0: Call    │
-                        └────────────────┘
-                          │
-                          │
-                          ▼
-                        ┌────────────────┐
-                        │   bb1: Goto    │
-                        └────────────────┘
-                          │
-                          │
-                          ▼
-    ┌─────────────┐     ┌────────────────┐
-    │  bb4: Call  │ ◀── │ bb2: SwitchInt │
-    └─────────────┘     └────────────────┘
-      │                   │
-      │                   │
-      ▼                   ▼
-    ┌─────────────┐     ┌────────────────┐
-    │ bb6: Return │     │   bb3: Call    │
-    └─────────────┘     └────────────────┘
-                          │
-                          │
-                          ▼
-                        ┌────────────────┐
-                        │  bb5: Return   │
-                        └────────────────┘
-    */
-    mir_body
-}
-
-macro_rules! assert_successors {
-    ($basic_coverage_blocks:ident, $i:ident, [$($successor:ident),*]) => {
-        let mut successors = $basic_coverage_blocks.successors[$i].clone();
-        successors.sort_unstable();
-        assert_eq!(successors, vec![$($successor),*]);
-    }
-}
-
-#[test]
-fn test_covgraph_goto_switchint() {
-    let mir_body = goto_switchint();
-    if false {
-        eprintln!("basic_blocks = {}", debug_basic_blocks(&mir_body));
-    }
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    print_coverage_graphviz("covgraph_goto_switchint ", &mir_body, &basic_coverage_blocks);
-    /*
-    ┌──────────────┐     ┌─────────────────┐
-    │ bcb2: Return │ ◀── │ bcb0: SwitchInt │
-    └──────────────┘     └─────────────────┘
-                           │
-                           │
-                           ▼
-                         ┌─────────────────┐
-                         │  bcb1: Return   │
-                         └─────────────────┘
-    */
-    assert_eq!(
-        basic_coverage_blocks.num_nodes(),
-        3,
-        "basic_coverage_blocks: {:?}",
-        basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
-    );
-
-    let_bcb!(0);
-    let_bcb!(1);
-    let_bcb!(2);
-
-    assert_successors!(basic_coverage_blocks, bcb0, [bcb1, bcb2]);
-    assert_successors!(basic_coverage_blocks, bcb1, []);
-    assert_successors!(basic_coverage_blocks, bcb2, []);
-}
-
-/// Create a mock `Body` with a loop.
-fn switchint_then_loop_else_return() -> Body<'a> {
-    let mut blocks = MockBlocks::new();
-    let start = blocks.call(None);
-    let switchint = blocks.switchint(Some(start));
-    let then_call = blocks.call(None);
-    blocks.set_branch(switchint, 0, then_call);
-    let backedge_goto = blocks.goto(Some(then_call));
-    blocks.link(backedge_goto, switchint);
-    let else_return = blocks.return_(None);
-    blocks.set_branch(switchint, 1, else_return);
-
-    let mir_body = blocks.to_body();
-    print_mir_graphviz("mir_switchint_then_loop_else_return", &mir_body);
-    /*
-                        ┌────────────────┐
-                        │   bb0: Call    │
-                        └────────────────┘
-                          │
-                          │
-                          ▼
-    ┌─────────────┐     ┌────────────────┐
-    │ bb4: Return │ ◀── │ bb1: SwitchInt │ ◀┐
-    └─────────────┘     └────────────────┘  │
-                          │                 │
-                          │                 │
-                          ▼                 │
-                        ┌────────────────┐  │
-                        │   bb2: Call    │  │
-                        └────────────────┘  │
-                          │                 │
-                          │                 │
-                          ▼                 │
-                        ┌────────────────┐  │
-                        │   bb3: Goto    │ ─┘
-                        └────────────────┘
-    */
-    mir_body
-}
-
-#[test]
-fn test_covgraph_switchint_then_loop_else_return() {
-    let mir_body = switchint_then_loop_else_return();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    print_coverage_graphviz(
-        "covgraph_switchint_then_loop_else_return",
-        &mir_body,
-        &basic_coverage_blocks,
-    );
-    /*
-                       ┌─────────────────┐
-                       │   bcb0: Call    │
-                       └─────────────────┘
-                         │
-                         │
-                         ▼
-    ┌────────────┐     ┌─────────────────┐
-    │ bcb3: Goto │ ◀── │ bcb1: SwitchInt │ ◀┐
-    └────────────┘     └─────────────────┘  │
-      │                  │                  │
-      │                  │                  │
-      │                  ▼                  │
-      │                ┌─────────────────┐  │
-      │                │  bcb2: Return   │  │
-      │                └─────────────────┘  │
-      │                                     │
-      └─────────────────────────────────────┘
-    */
-    assert_eq!(
-        basic_coverage_blocks.num_nodes(),
-        4,
-        "basic_coverage_blocks: {:?}",
-        basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
-    );
-
-    let_bcb!(0);
-    let_bcb!(1);
-    let_bcb!(2);
-    let_bcb!(3);
-
-    assert_successors!(basic_coverage_blocks, bcb0, [bcb1]);
-    assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]);
-    assert_successors!(basic_coverage_blocks, bcb2, []);
-    assert_successors!(basic_coverage_blocks, bcb3, [bcb1]);
-}
-
-/// Create a mock `Body` with nested loops.
-fn switchint_loop_then_inner_loop_else_break() -> Body<'a> {
-    let mut blocks = MockBlocks::new();
-    let start = blocks.call(None);
-    let switchint = blocks.switchint(Some(start));
-    let then_call = blocks.call(None);
-    blocks.set_branch(switchint, 0, then_call);
-    let else_return = blocks.return_(None);
-    blocks.set_branch(switchint, 1, else_return);
-
-    let inner_start = blocks.call(Some(then_call));
-    let inner_switchint = blocks.switchint(Some(inner_start));
-    let inner_then_call = blocks.call(None);
-    blocks.set_branch(inner_switchint, 0, inner_then_call);
-    let inner_backedge_goto = blocks.goto(Some(inner_then_call));
-    blocks.link(inner_backedge_goto, inner_switchint);
-    let inner_else_break_goto = blocks.goto(None);
-    blocks.set_branch(inner_switchint, 1, inner_else_break_goto);
-
-    let backedge_goto = blocks.goto(Some(inner_else_break_goto));
-    blocks.link(backedge_goto, switchint);
-
-    let mir_body = blocks.to_body();
-    print_mir_graphviz("mir_switchint_loop_then_inner_loop_else_break", &mir_body);
-    /*
-                        ┌────────────────┐
-                        │   bb0: Call    │
-                        └────────────────┘
-                          │
-                          │
-                          ▼
-    ┌─────────────┐     ┌────────────────┐
-    │ bb3: Return │ ◀── │ bb1: SwitchInt │ ◀─────┐
-    └─────────────┘     └────────────────┘       │
-                          │                      │
-                          │                      │
-                          ▼                      │
-                        ┌────────────────┐       │
-                        │   bb2: Call    │       │
-                        └────────────────┘       │
-                          │                      │
-                          │                      │
-                          ▼                      │
-                        ┌────────────────┐       │
-                        │   bb4: Call    │       │
-                        └────────────────┘       │
-                          │                      │
-                          │                      │
-                          ▼                      │
-    ┌─────────────┐     ┌────────────────┐       │
-    │  bb8: Goto  │ ◀── │ bb5: SwitchInt │ ◀┐    │
-    └─────────────┘     └────────────────┘  │    │
-      │                   │                 │    │
-      │                   │                 │    │
-      ▼                   ▼                 │    │
-    ┌─────────────┐     ┌────────────────┐  │    │
-    │  bb9: Goto  │ ─┐  │   bb6: Call    │  │    │
-    └─────────────┘  │  └────────────────┘  │    │
-                     │    │                 │    │
-                     │    │                 │    │
-                     │    ▼                 │    │
-                     │  ┌────────────────┐  │    │
-                     │  │   bb7: Goto    │ ─┘    │
-                     │  └────────────────┘       │
-                     │                           │
-                     └───────────────────────────┘
-    */
-    mir_body
-}
-
-#[test]
-fn test_covgraph_switchint_loop_then_inner_loop_else_break() {
-    let mir_body = switchint_loop_then_inner_loop_else_break();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    print_coverage_graphviz(
-        "covgraph_switchint_loop_then_inner_loop_else_break",
-        &mir_body,
-        &basic_coverage_blocks,
-    );
-    /*
-                         ┌─────────────────┐
-                         │   bcb0: Call    │
-                         └─────────────────┘
-                           │
-                           │
-                           ▼
-    ┌──────────────┐     ┌─────────────────┐
-    │ bcb2: Return │ ◀── │ bcb1: SwitchInt │ ◀┐
-    └──────────────┘     └─────────────────┘  │
-                           │                  │
-                           │                  │
-                           ▼                  │
-                         ┌─────────────────┐  │
-                         │   bcb3: Call    │  │
-                         └─────────────────┘  │
-                           │                  │
-                           │                  │
-                           ▼                  │
-    ┌──────────────┐     ┌─────────────────┐  │
-    │  bcb6: Goto  │ ◀── │ bcb4: SwitchInt │ ◀┼────┐
-    └──────────────┘     └─────────────────┘  │    │
-      │                    │                  │    │
-      │                    │                  │    │
-      │                    ▼                  │    │
-      │                  ┌─────────────────┐  │    │
-      │                  │   bcb5: Goto    │ ─┘    │
-      │                  └─────────────────┘       │
-      │                                            │
-      └────────────────────────────────────────────┘
-    */
-    assert_eq!(
-        basic_coverage_blocks.num_nodes(),
-        7,
-        "basic_coverage_blocks: {:?}",
-        basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
-    );
-
-    let_bcb!(0);
-    let_bcb!(1);
-    let_bcb!(2);
-    let_bcb!(3);
-    let_bcb!(4);
-    let_bcb!(5);
-    let_bcb!(6);
-
-    assert_successors!(basic_coverage_blocks, bcb0, [bcb1]);
-    assert_successors!(basic_coverage_blocks, bcb1, [bcb2, bcb3]);
-    assert_successors!(basic_coverage_blocks, bcb2, []);
-    assert_successors!(basic_coverage_blocks, bcb3, [bcb4]);
-    assert_successors!(basic_coverage_blocks, bcb4, [bcb5, bcb6]);
-    assert_successors!(basic_coverage_blocks, bcb5, [bcb1]);
-    assert_successors!(basic_coverage_blocks, bcb6, [bcb4]);
-}
-
-#[test]
-fn test_find_loop_backedges_none() {
-    let mir_body = goto_switchint();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    if false {
-        eprintln!(
-            "basic_coverage_blocks = {:?}",
-            basic_coverage_blocks.iter_enumerated().collect::<Vec<_>>()
-        );
-        eprintln!("successors = {:?}", basic_coverage_blocks.successors);
-    }
-    let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
-    assert_eq!(
-        backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
-        0,
-        "backedges: {:?}",
-        backedges
-    );
-}
-
-#[test]
-fn test_find_loop_backedges_one() {
-    let mir_body = switchint_then_loop_else_return();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
-    assert_eq!(
-        backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
-        1,
-        "backedges: {:?}",
-        backedges
-    );
-
-    let_bcb!(1);
-    let_bcb!(3);
-
-    assert_eq!(backedges[bcb1], vec![bcb3]);
-}
-
-#[test]
-fn test_find_loop_backedges_two() {
-    let mir_body = switchint_loop_then_inner_loop_else_break();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    let backedges = graph::find_loop_backedges(&basic_coverage_blocks);
-    assert_eq!(
-        backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::<usize>(),
-        2,
-        "backedges: {:?}",
-        backedges
-    );
-
-    let_bcb!(1);
-    let_bcb!(4);
-    let_bcb!(5);
-    let_bcb!(6);
-
-    assert_eq!(backedges[bcb1], vec![bcb5]);
-    assert_eq!(backedges[bcb4], vec![bcb6]);
-}
-
-#[test]
-fn test_traverse_coverage_with_loops() {
-    let mir_body = switchint_loop_then_inner_loop_else_break();
-    let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-    let mut traversed_in_order = Vec::new();
-    let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks);
-    while let Some(bcb) = traversal.next(&basic_coverage_blocks) {
-        traversed_in_order.push(bcb);
-    }
-
-    let_bcb!(6);
-
-    // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except*
-    // bcb6 are inside the first loop.
-    assert_eq!(
-        *traversed_in_order.last().expect("should have elements"),
-        bcb6,
-        "bcb6 should not be visited until all nodes inside the first loop have been visited"
-    );
-}
-
-fn synthesize_body_span_from_terminators(mir_body: &Body<'_>) -> Span {
-    let mut some_span: Option<Span> = None;
-    for (_, data) in mir_body.basic_blocks().iter_enumerated() {
-        let term_span = data.terminator().source_info.span;
-        if let Some(span) = some_span.as_mut() {
-            *span = span.to(term_span);
-        } else {
-            some_span = Some(term_span)
-        }
-    }
-    some_span.expect("body must have at least one BasicBlock")
-}
-
-#[test]
-fn test_make_bcb_counters() {
-    rustc_span::create_default_session_globals_then(|| {
-        let mir_body = goto_switchint();
-        let body_span = synthesize_body_span_from_terminators(&mir_body);
-        let mut basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body);
-        let mut coverage_spans = Vec::new();
-        for (bcb, data) in basic_coverage_blocks.iter_enumerated() {
-            if let Some(span) = spans::filtered_terminator_span(data.terminator(&mir_body)) {
-                coverage_spans.push(spans::CoverageSpan::for_terminator(
-                    spans::function_source_span(span, body_span),
-                    span,
-                    bcb,
-                    data.last_bb(),
-                ));
-            }
-        }
-        let mut coverage_counters = counters::CoverageCounters::new(0);
-        let intermediate_expressions = coverage_counters
-            .make_bcb_counters(&mut basic_coverage_blocks, &coverage_spans)
-            .expect("should be Ok");
-        assert_eq!(intermediate_expressions.len(), 0);
-
-        let_bcb!(1);
-        assert_eq!(
-            1, // coincidentally, bcb1 has a `Counter` with id = 1
-            match basic_coverage_blocks[bcb1].counter().expect("should have a counter") {
-                CoverageKind::Counter { id, .. } => id,
-                _ => panic!("expected a Counter"),
-            }
-            .as_u32()
-        );
-
-        let_bcb!(2);
-        assert_eq!(
-            2, // coincidentally, bcb2 has a `Counter` with id = 2
-            match basic_coverage_blocks[bcb2].counter().expect("should have a counter") {
-                CoverageKind::Counter { id, .. } => id,
-                _ => panic!("expected a Counter"),
-            }
-            .as_u32()
-        );
-    });
-}
diff --git a/compiler/rustc_mir/src/transform/deaggregator.rs b/compiler/rustc_mir/src/transform/deaggregator.rs
deleted file mode 100644
index 5bd7256c666..00000000000
--- a/compiler/rustc_mir/src/transform/deaggregator.rs
+++ /dev/null
@@ -1,49 +0,0 @@
-use crate::transform::MirPass;
-use crate::util::expand_aggregate;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-pub struct Deaggregator;
-
-impl<'tcx> MirPass<'tcx> for Deaggregator {
-    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;
-        for bb in basic_blocks {
-            bb.expand_statements(|stmt| {
-                // FIXME(eddyb) don't match twice on `stmt.kind` (post-NLL).
-                match stmt.kind {
-                    // FIXME(#48193) Deaggregate arrays when it's cheaper to do so.
-                    StatementKind::Assign(box (
-                        _,
-                        Rvalue::Aggregate(box AggregateKind::Array(_), _),
-                    )) => {
-                        return None;
-                    }
-                    StatementKind::Assign(box (_, Rvalue::Aggregate(_, _))) => {}
-                    _ => return None,
-                }
-
-                let stmt = stmt.replace_nop();
-                let source_info = stmt.source_info;
-                let (lhs, kind, operands) = match stmt.kind {
-                    StatementKind::Assign(box (lhs, Rvalue::Aggregate(kind, operands))) => {
-                        (lhs, kind, operands)
-                    }
-                    _ => bug!(),
-                };
-
-                Some(expand_aggregate(
-                    lhs,
-                    operands.into_iter().map(|op| {
-                        let ty = op.ty(local_decls, tcx);
-                        (op, ty)
-                    }),
-                    *kind,
-                    source_info,
-                    tcx,
-                ))
-            });
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
deleted file mode 100644
index 912505c6598..00000000000
--- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs
+++ /dev/null
@@ -1,189 +0,0 @@
-//! This pass finds basic blocks that are completely equal,
-//! and replaces all uses with just one of them.
-
-use std::{collections::hash_map::Entry, hash::Hash, hash::Hasher, iter};
-
-use crate::transform::MirPass;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::mir::visit::MutVisitor;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-use super::simplify::simplify_cfg;
-
-pub struct DeduplicateBlocks;
-
-impl<'tcx> MirPass<'tcx> for DeduplicateBlocks {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
-        debug!("Running DeduplicateBlocks on `{:?}`", body.source);
-        let duplicates = find_duplicates(body);
-        let has_opts_to_apply = !duplicates.is_empty();
-
-        if has_opts_to_apply {
-            let mut opt_applier = OptApplier { tcx, duplicates };
-            opt_applier.visit_body(body);
-            simplify_cfg(tcx, body);
-        }
-    }
-}
-
-struct OptApplier<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    duplicates: FxHashMap<BasicBlock, BasicBlock>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for OptApplier<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
-        for target in terminator.successors_mut() {
-            if let Some(replacement) = self.duplicates.get(target) {
-                debug!("SUCCESS: Replacing: `{:?}` with `{:?}`", target, replacement);
-                *target = *replacement;
-            }
-        }
-
-        self.super_terminator(terminator, location);
-    }
-}
-
-fn find_duplicates<'a, 'tcx>(body: &'a Body<'tcx>) -> FxHashMap<BasicBlock, BasicBlock> {
-    let mut duplicates = FxHashMap::default();
-
-    let bbs_to_go_through =
-        body.basic_blocks().iter_enumerated().filter(|(_, bbd)| !bbd.is_cleanup).count();
-
-    let mut same_hashes =
-        FxHashMap::with_capacity_and_hasher(bbs_to_go_through, Default::default());
-
-    // Go through the basic blocks backwards. This means that in case of duplicates,
-    // we can use the basic block with the highest index as the replacement for all lower ones.
-    // For example, if bb1, bb2 and bb3 are duplicates, we will first insert bb3 in same_hashes.
-    // Then we will see that bb2 is a duplicate of bb3,
-    // and insert bb2 with the replacement bb3 in the duplicates list.
-    // When we see bb1, we see that it is a duplicate of bb3, and therefore insert it in the duplicates list
-    // with replacement bb3.
-    // When the duplicates are removed, we will end up with only bb3.
-    for (bb, bbd) in body.basic_blocks().iter_enumerated().rev().filter(|(_, bbd)| !bbd.is_cleanup)
-    {
-        // Basic blocks can get really big, so to avoid checking for duplicates in basic blocks
-        // that are unlikely to have duplicates, we stop early. The early bail number has been
-        // found experimentally by eprintln while compiling the crates in the rustc-perf suite.
-        if bbd.statements.len() > 10 {
-            continue;
-        }
-
-        let to_hash = BasicBlockHashable { basic_block_data: bbd };
-        let entry = same_hashes.entry(to_hash);
-        match entry {
-            Entry::Occupied(occupied) => {
-                // The basic block was already in the hashmap, which means we have a duplicate
-                let value = *occupied.get();
-                debug!("Inserting {:?} -> {:?}", bb, value);
-                duplicates.try_insert(bb, value).expect("key was already inserted");
-            }
-            Entry::Vacant(vacant) => {
-                vacant.insert(bb);
-            }
-        }
-    }
-
-    duplicates
-}
-
-struct BasicBlockHashable<'tcx, 'a> {
-    basic_block_data: &'a BasicBlockData<'tcx>,
-}
-
-impl<'tcx, 'a> Hash for BasicBlockHashable<'tcx, 'a> {
-    fn hash<H: Hasher>(&self, state: &mut H) {
-        hash_statements(state, self.basic_block_data.statements.iter());
-        // Note that since we only hash the kind, we lose span information if we deduplicate the blocks
-        self.basic_block_data.terminator().kind.hash(state);
-    }
-}
-
-impl<'tcx, 'a> Eq for BasicBlockHashable<'tcx, 'a> {}
-
-impl<'tcx, 'a> PartialEq for BasicBlockHashable<'tcx, 'a> {
-    fn eq(&self, other: &Self) -> bool {
-        self.basic_block_data.statements.len() == other.basic_block_data.statements.len()
-            && &self.basic_block_data.terminator().kind == &other.basic_block_data.terminator().kind
-            && iter::zip(&self.basic_block_data.statements, &other.basic_block_data.statements)
-                .all(|(x, y)| statement_eq(&x.kind, &y.kind))
-    }
-}
-
-fn hash_statements<'a, 'tcx, H: Hasher>(
-    hasher: &mut H,
-    iter: impl Iterator<Item = &'a Statement<'tcx>>,
-) where
-    'tcx: 'a,
-{
-    for stmt in iter {
-        statement_hash(hasher, &stmt.kind);
-    }
-}
-
-fn statement_hash<'tcx, H: Hasher>(hasher: &mut H, stmt: &StatementKind<'tcx>) {
-    match stmt {
-        StatementKind::Assign(box (place, rvalue)) => {
-            place.hash(hasher);
-            rvalue_hash(hasher, rvalue)
-        }
-        x => x.hash(hasher),
-    };
-}
-
-fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'tcx>) {
-    match rvalue {
-        Rvalue::Use(op) => operand_hash(hasher, op),
-        x => x.hash(hasher),
-    };
-}
-
-fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'tcx>) {
-    match operand {
-        Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher),
-        x => x.hash(hasher),
-    };
-}
-
-fn statement_eq<'tcx>(lhs: &StatementKind<'tcx>, rhs: &StatementKind<'tcx>) -> bool {
-    let res = match (lhs, rhs) {
-        (
-            StatementKind::Assign(box (place, rvalue)),
-            StatementKind::Assign(box (place2, rvalue2)),
-        ) => place == place2 && rvalue_eq(rvalue, rvalue2),
-        (x, y) => x == y,
-    };
-    debug!("statement_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
-    res
-}
-
-fn rvalue_eq(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
-    let res = match (lhs, rhs) {
-        (Rvalue::Use(op1), Rvalue::Use(op2)) => operand_eq(op1, op2),
-        (x, y) => x == y,
-    };
-    debug!("rvalue_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
-    res
-}
-
-fn operand_eq(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
-    let res = match (lhs, rhs) {
-        (
-            Operand::Constant(box Constant { user_ty: _, literal, span: _ }),
-            Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }),
-        ) => literal == literal2,
-        (x, y) => x == y,
-    };
-    debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
-    res
-}
diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs
deleted file mode 100644
index 4f5a467a6ee..00000000000
--- a/compiler/rustc_mir/src/transform/dest_prop.rs
+++ /dev/null
@@ -1,1039 +0,0 @@
-//! Propagates assignment destinations backwards in the CFG to eliminate redundant assignments.
-//!
-//! # Motivation
-//!
-//! MIR building can insert a lot of redundant copies, and Rust code in general often tends to move
-//! values around a lot. The result is a lot of assignments of the form `dest = {move} src;` in MIR.
-//! MIR building for constants in particular tends to create additional locals that are only used
-//! inside a single block to shuffle a value around unnecessarily.
-//!
-//! LLVM by itself is not good enough at eliminating these redundant copies (eg. see
-//! <https://github.com/rust-lang/rust/issues/32966>), so this leaves some performance on the table
-//! that we can regain by implementing an optimization for removing these assign statements in rustc
-//! itself. When this optimization runs fast enough, it can also speed up the constant evaluation
-//! and code generation phases of rustc due to the reduced number of statements and locals.
-//!
-//! # The Optimization
-//!
-//! Conceptually, this optimization is "destination propagation". It is similar to the Named Return
-//! Value Optimization, or NRVO, known from the C++ world, except that it isn't limited to return
-//! values or the return place `_0`. On a very high level, independent of the actual implementation
-//! details, it does the following:
-//!
-//! 1) Identify `dest = src;` statements that can be soundly eliminated.
-//! 2) Replace all mentions of `src` with `dest` ("unifying" them and propagating the destination
-//!    backwards).
-//! 3) Delete the `dest = src;` statement (by making it a `nop`).
-//!
-//! Step 1) is by far the hardest, so it is explained in more detail below.
-//!
-//! ## Soundness
-//!
-//! Given an `Assign` statement `dest = src;`, where `dest` is a `Place` and `src` is an `Rvalue`,
-//! there are a few requirements that must hold for the optimization to be sound:
-//!
-//! * `dest` must not contain any *indirection* through a pointer. It must access part of the base
-//!   local. Otherwise it might point to arbitrary memory that is hard to track.
-//!
-//!   It must also not contain any indexing projections, since those take an arbitrary `Local` as
-//!   the index, and that local might only be initialized shortly before `dest` is used.
-//!
-//!   Subtle case: If `dest` is a, or projects through a union, then we have to make sure that there
-//!   remains an assignment to it, since that sets the "active field" of the union. But if `src` is
-//!   a ZST, it might not be initialized, so there might not be any use of it before the assignment,
-//!   and performing the optimization would simply delete the assignment, leaving `dest`
-//!   uninitialized.
-//!
-//! * `src` must be a bare `Local` without any indirections or field projections (FIXME: Is this a
-//!   fundamental restriction or just current impl state?). It can be copied or moved by the
-//!   assignment.
-//!
-//! * The `dest` and `src` locals must never be [*live*][liveness] at the same time. If they are, it
-//!   means that they both hold a (potentially different) value that is needed by a future use of
-//!   the locals. Unifying them would overwrite one of the values.
-//!
-//!   Note that computing liveness of locals that have had their address taken is more difficult:
-//!   Short of doing full escape analysis on the address/pointer/reference, the pass would need to
-//!   assume that any operation that can potentially involve opaque user code (such as function
-//!   calls, destructors, and inline assembly) may access any local that had its address taken
-//!   before that point.
-//!
-//! Here, the first two conditions are simple structural requirements on the `Assign` statements
-//! that can be trivially checked. The liveness requirement however is more difficult and costly to
-//! check.
-//!
-//! ## Previous Work
-//!
-//! A [previous attempt] at implementing an optimization like this turned out to be a significant
-//! regression in compiler performance. Fixing the regressions introduced a lot of undesirable
-//! complexity to the implementation.
-//!
-//! A [subsequent approach] tried to avoid the costly computation by limiting itself to acyclic
-//! CFGs, but still turned out to be far too costly to run due to suboptimal performance within
-//! individual basic blocks, requiring a walk across the entire block for every assignment found
-//! within the block. For the `tuple-stress` benchmark, which has 458745 statements in a single
-//! block, this proved to be far too costly.
-//!
-//! Since the first attempt at this, the compiler has improved dramatically, and new analysis
-//! frameworks have been added that should make this approach viable without requiring a limited
-//! approach that only works for some classes of CFGs:
-//! - rustc now has a powerful dataflow analysis framework that can handle forwards and backwards
-//!   analyses efficiently.
-//! - Layout optimizations for generators have been added to improve code generation for
-//!   async/await, which are very similar in spirit to what this optimization does. Both walk the
-//!   MIR and record conflicting uses of locals in a `BitMatrix`.
-//!
-//! Also, rustc now has a simple NRVO pass (see `nrvo.rs`), which handles a subset of the cases that
-//! this destination propagation pass handles, proving that similar optimizations can be performed
-//! on MIR.
-//!
-//! ## Pre/Post Optimization
-//!
-//! It is recommended to run `SimplifyCfg` and then `SimplifyLocals` some time after this pass, as
-//! it replaces the eliminated assign statements with `nop`s and leaves unused locals behind.
-//!
-//! [liveness]: https://en.wikipedia.org/wiki/Live_variable_analysis
-//! [previous attempt]: https://github.com/rust-lang/rust/pull/47954
-//! [subsequent approach]: https://github.com/rust-lang/rust/pull/71003
-
-use crate::dataflow::impls::{MaybeInitializedLocals, MaybeLiveLocals};
-use crate::dataflow::Analysis;
-use crate::{
-    transform::MirPass,
-    util::{dump_mir, PassWhere},
-};
-use itertools::Itertools;
-use rustc_data_structures::unify::{InPlaceUnificationTable, UnifyKey};
-use rustc_index::{
-    bit_set::{BitMatrix, BitSet},
-    vec::IndexVec,
-};
-use rustc_middle::mir::tcx::PlaceTy;
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
-use rustc_middle::mir::{
-    traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
-    Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
-};
-use rustc_middle::ty::TyCtxt;
-
-// Empirical measurements have resulted in some observations:
-// - Running on a body with a single block and 500 locals takes barely any time
-// - Running on a body with ~400 blocks and ~300 relevant locals takes "too long"
-// ...so we just limit both to somewhat reasonable-ish looking values.
-const MAX_LOCALS: usize = 500;
-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>) {
-        //  FIXME(#79191, #82678)
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
-
-        // Only run at mir-opt-level=3 or higher for now (we don't fix up debuginfo and remove
-        // storage statements at the moment).
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
-
-        let def_id = body.source.def_id();
-
-        let candidates = find_candidates(tcx, body);
-        if candidates.is_empty() {
-            debug!("{:?}: no dest prop candidates, done", def_id);
-            return;
-        }
-
-        // Collect all locals we care about. We only compute conflicts for these to save time.
-        let mut relevant_locals = BitSet::new_empty(body.local_decls.len());
-        for CandidateAssignment { dest, src, loc: _ } in &candidates {
-            relevant_locals.insert(dest.local);
-            relevant_locals.insert(*src);
-        }
-
-        // This pass unfortunately has `O(l² * s)` performance, where `l` is the number of locals
-        // and `s` is the number of statements and terminators in the function.
-        // To prevent blowing up compile times too much, we bail out when there are too many locals.
-        let relevant = relevant_locals.count();
-        debug!(
-            "{:?}: {} locals ({} relevant), {} blocks",
-            def_id,
-            body.local_decls.len(),
-            relevant,
-            body.basic_blocks().len()
-        );
-        if relevant > MAX_LOCALS {
-            warn!(
-                "too many candidate locals in {:?} ({}, max is {}), not optimizing",
-                def_id, relevant, MAX_LOCALS
-            );
-            return;
-        }
-        if body.basic_blocks().len() > MAX_BLOCKS {
-            warn!(
-                "too many blocks in {:?} ({}, max is {}), not optimizing",
-                def_id,
-                body.basic_blocks().len(),
-                MAX_BLOCKS
-            );
-            return;
-        }
-
-        let mut conflicts = Conflicts::build(tcx, body, &relevant_locals);
-
-        let mut replacements = Replacements::new(body.local_decls.len());
-        for candidate @ CandidateAssignment { dest, src, loc } in candidates {
-            // Merge locals that don't conflict.
-            if !conflicts.can_unify(dest.local, src) {
-                debug!("at assignment {:?}, conflict {:?} vs. {:?}", loc, dest.local, src);
-                continue;
-            }
-
-            if replacements.for_src(candidate.src).is_some() {
-                debug!("src {:?} already has replacement", candidate.src);
-                continue;
-            }
-
-            if !tcx.consider_optimizing(|| {
-                format!("DestinationPropagation {:?} {:?}", def_id, candidate)
-            }) {
-                break;
-            }
-
-            replacements.push(candidate);
-            conflicts.unify(candidate.src, candidate.dest.local);
-        }
-
-        replacements.flatten(tcx);
-
-        debug!("replacements {:?}", replacements.map);
-
-        Replacer { tcx, replacements, place_elem_cache: Vec::new() }.visit_body(body);
-
-        // FIXME fix debug info
-    }
-}
-
-#[derive(Debug, Eq, PartialEq, Copy, Clone)]
-struct UnifyLocal(Local);
-
-impl From<Local> for UnifyLocal {
-    fn from(l: Local) -> Self {
-        Self(l)
-    }
-}
-
-impl UnifyKey for UnifyLocal {
-    type Value = ();
-    fn index(&self) -> u32 {
-        self.0.as_u32()
-    }
-    fn from_index(u: u32) -> Self {
-        Self(Local::from_u32(u))
-    }
-    fn tag() -> &'static str {
-        "UnifyLocal"
-    }
-}
-
-struct Replacements<'tcx> {
-    /// Maps locals to their replacement.
-    map: IndexVec<Local, Option<Place<'tcx>>>,
-
-    /// Whose locals' live ranges to kill.
-    kill: BitSet<Local>,
-}
-
-impl Replacements<'tcx> {
-    fn new(locals: usize) -> Self {
-        Self { map: IndexVec::from_elem_n(None, locals), kill: BitSet::new_empty(locals) }
-    }
-
-    fn push(&mut self, candidate: CandidateAssignment<'tcx>) {
-        trace!("Replacements::push({:?})", candidate);
-        let entry = &mut self.map[candidate.src];
-        assert!(entry.is_none());
-
-        *entry = Some(candidate.dest);
-        self.kill.insert(candidate.src);
-        self.kill.insert(candidate.dest.local);
-    }
-
-    /// Applies the stored replacements to all replacements, until no replacements would result in
-    /// locals that need further replacements when applied.
-    fn flatten(&mut self, tcx: TyCtxt<'tcx>) {
-        // Note: This assumes that there are no cycles in the replacements, which is enforced via
-        // `self.unified_locals`. Otherwise this can cause an infinite loop.
-
-        for local in self.map.indices() {
-            if let Some(replacement) = self.map[local] {
-                // Substitute the base local of `replacement` until fixpoint.
-                let mut base = replacement.local;
-                let mut reversed_projection_slices = Vec::with_capacity(1);
-                while let Some(replacement_for_replacement) = self.map[base] {
-                    base = replacement_for_replacement.local;
-                    reversed_projection_slices.push(replacement_for_replacement.projection);
-                }
-
-                let projection: Vec<_> = reversed_projection_slices
-                    .iter()
-                    .rev()
-                    .flat_map(|projs| projs.iter())
-                    .chain(replacement.projection.iter())
-                    .collect();
-                let projection = tcx.intern_place_elems(&projection);
-
-                // Replace with the final `Place`.
-                self.map[local] = Some(Place { local: base, projection });
-            }
-        }
-    }
-
-    fn for_src(&self, src: Local) -> Option<Place<'tcx>> {
-        self.map[src]
-    }
-}
-
-struct Replacer<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    replacements: Replacements<'tcx>,
-    place_elem_cache: Vec<PlaceElem<'tcx>>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
-    fn tcx<'a>(&'a self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, context: PlaceContext, location: Location) {
-        if context.is_use() && self.replacements.for_src(*local).is_some() {
-            bug!(
-                "use of local {:?} should have been replaced by visit_place; context={:?}, loc={:?}",
-                local,
-                context,
-                location,
-            );
-        }
-    }
-
-    fn process_projection_elem(
-        &mut self,
-        elem: PlaceElem<'tcx>,
-        _: Location,
-    ) -> Option<PlaceElem<'tcx>> {
-        match elem {
-            PlaceElem::Index(local) => {
-                if let Some(replacement) = self.replacements.for_src(local) {
-                    bug!(
-                        "cannot replace {:?} with {:?} in index projection {:?}",
-                        local,
-                        replacement,
-                        elem,
-                    );
-                } else {
-                    None
-                }
-            }
-            _ => None,
-        }
-    }
-
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if let Some(replacement) = self.replacements.for_src(place.local) {
-            // Rebase `place`s projections onto `replacement`'s.
-            self.place_elem_cache.clear();
-            self.place_elem_cache.extend(replacement.projection.iter().chain(place.projection));
-            let projection = self.tcx.intern_place_elems(&self.place_elem_cache);
-            let new_place = Place { local: replacement.local, projection };
-
-            debug!("Replacer: {:?} -> {:?}", place, new_place);
-            *place = new_place;
-        }
-
-        self.super_place(place, context, location);
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        self.super_statement(statement, location);
-
-        match &statement.kind {
-            // FIXME: Don't delete storage statements, merge the live ranges instead
-            StatementKind::StorageDead(local) | StatementKind::StorageLive(local)
-                if self.replacements.kill.contains(*local) =>
-            {
-                statement.make_nop()
-            }
-
-            StatementKind::Assign(box (dest, rvalue)) => {
-                match rvalue {
-                    Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) => {
-                        // These might've been turned into self-assignments by the replacement
-                        // (this includes the original statement we wanted to eliminate).
-                        if dest == place {
-                            debug!("{:?} turned into self-assignment, deleting", location);
-                            statement.make_nop();
-                        }
-                    }
-                    _ => {}
-                }
-            }
-
-            _ => {}
-        }
-    }
-}
-
-struct Conflicts<'a> {
-    relevant_locals: &'a BitSet<Local>,
-
-    /// The conflict matrix. It is always symmetric and the adjacency matrix of the corresponding
-    /// conflict graph.
-    matrix: BitMatrix<Local, Local>,
-
-    /// Preallocated `BitSet` used by `unify`.
-    unify_cache: BitSet<Local>,
-
-    /// Tracks locals that have been merged together to prevent cycles and propagate conflicts.
-    unified_locals: InPlaceUnificationTable<UnifyLocal>,
-}
-
-impl Conflicts<'a> {
-    fn build<'tcx>(
-        tcx: TyCtxt<'tcx>,
-        body: &'_ Body<'tcx>,
-        relevant_locals: &'a BitSet<Local>,
-    ) -> Self {
-        // We don't have to look out for locals that have their address taken, since
-        // `find_candidates` already takes care of that.
-
-        let conflicts = BitMatrix::from_row_n(
-            &BitSet::new_empty(body.local_decls.len()),
-            body.local_decls.len(),
-        );
-
-        let mut init = MaybeInitializedLocals
-            .into_engine(tcx, body)
-            .iterate_to_fixpoint()
-            .into_results_cursor(body);
-        let mut live =
-            MaybeLiveLocals.into_engine(tcx, body).iterate_to_fixpoint().into_results_cursor(body);
-
-        let mut reachable = None;
-        dump_mir(tcx, None, "DestinationPropagation-dataflow", &"", body, |pass_where, w| {
-            let reachable = reachable.get_or_insert_with(|| traversal::reachable_as_bitset(body));
-
-            match pass_where {
-                PassWhere::BeforeLocation(loc) if reachable.contains(loc.block) => {
-                    init.seek_before_primary_effect(loc);
-                    live.seek_after_primary_effect(loc);
-
-                    writeln!(w, "        // init: {:?}", init.get())?;
-                    writeln!(w, "        // live: {:?}", live.get())?;
-                }
-                PassWhere::AfterTerminator(bb) if reachable.contains(bb) => {
-                    let loc = body.terminator_loc(bb);
-                    init.seek_after_primary_effect(loc);
-                    live.seek_before_primary_effect(loc);
-
-                    writeln!(w, "        // init: {:?}", init.get())?;
-                    writeln!(w, "        // live: {:?}", live.get())?;
-                }
-
-                PassWhere::BeforeBlock(bb) if reachable.contains(bb) => {
-                    init.seek_to_block_start(bb);
-                    live.seek_to_block_start(bb);
-
-                    writeln!(w, "    // init: {:?}", init.get())?;
-                    writeln!(w, "    // live: {:?}", live.get())?;
-                }
-
-                PassWhere::BeforeCFG | PassWhere::AfterCFG | PassWhere::AfterLocation(_) => {}
-
-                PassWhere::BeforeLocation(_) | PassWhere::AfterTerminator(_) => {
-                    writeln!(w, "        // init: <unreachable>")?;
-                    writeln!(w, "        // live: <unreachable>")?;
-                }
-
-                PassWhere::BeforeBlock(_) => {
-                    writeln!(w, "    // init: <unreachable>")?;
-                    writeln!(w, "    // live: <unreachable>")?;
-                }
-            }
-
-            Ok(())
-        });
-
-        let mut this = Self {
-            relevant_locals,
-            matrix: conflicts,
-            unify_cache: BitSet::new_empty(body.local_decls.len()),
-            unified_locals: {
-                let mut table = InPlaceUnificationTable::new();
-                // Pre-fill table with all locals (this creates N nodes / "connected" components,
-                // "graph"-ically speaking).
-                for local in 0..body.local_decls.len() {
-                    assert_eq!(table.new_key(()), UnifyLocal(Local::from_usize(local)));
-                }
-                table
-            },
-        };
-
-        let mut live_and_init_locals = Vec::new();
-
-        // Visit only reachable basic blocks. The exact order is not important.
-        for (block, data) in traversal::preorder(body) {
-            // We need to observe the dataflow state *before* all possible locations (statement or
-            // terminator) in each basic block, and then observe the state *after* the terminator
-            // effect is applied. As long as neither `init` nor `borrowed` has a "before" effect,
-            // we will observe all possible dataflow states.
-
-            // Since liveness is a backwards analysis, we need to walk the results backwards. To do
-            // that, we first collect in the `MaybeInitializedLocals` results in a forwards
-            // traversal.
-
-            live_and_init_locals.resize_with(data.statements.len() + 1, || {
-                BitSet::new_empty(body.local_decls.len())
-            });
-
-            // First, go forwards for `MaybeInitializedLocals` and apply intra-statement/terminator
-            // conflicts.
-            for (i, statement) in data.statements.iter().enumerate() {
-                this.record_statement_conflicts(statement);
-
-                let loc = Location { block, statement_index: i };
-                init.seek_before_primary_effect(loc);
-
-                live_and_init_locals[i].clone_from(init.get());
-            }
-
-            this.record_terminator_conflicts(data.terminator());
-            let term_loc = Location { block, statement_index: data.statements.len() };
-            init.seek_before_primary_effect(term_loc);
-            live_and_init_locals[term_loc.statement_index].clone_from(init.get());
-
-            // Now, go backwards and union with the liveness results.
-            for statement_index in (0..=data.statements.len()).rev() {
-                let loc = Location { block, statement_index };
-                live.seek_after_primary_effect(loc);
-
-                live_and_init_locals[statement_index].intersect(live.get());
-
-                trace!("record conflicts at {:?}", loc);
-
-                this.record_dataflow_conflicts(&mut live_and_init_locals[statement_index]);
-            }
-
-            init.seek_to_block_end(block);
-            live.seek_to_block_end(block);
-            let mut conflicts = init.get().clone();
-            conflicts.intersect(live.get());
-            trace!("record conflicts at end of {:?}", block);
-
-            this.record_dataflow_conflicts(&mut conflicts);
-        }
-
-        this
-    }
-
-    fn record_dataflow_conflicts(&mut self, new_conflicts: &mut BitSet<Local>) {
-        // Remove all locals that are not candidates.
-        new_conflicts.intersect(self.relevant_locals);
-
-        for local in new_conflicts.iter() {
-            self.matrix.union_row_with(&new_conflicts, local);
-        }
-    }
-
-    fn record_local_conflict(&mut self, a: Local, b: Local, why: &str) {
-        trace!("conflict {:?} <-> {:?} due to {}", a, b, why);
-        self.matrix.insert(a, b);
-        self.matrix.insert(b, a);
-    }
-
-    /// Records locals that must not overlap during the evaluation of `stmt`. These locals conflict
-    /// and must not be merged.
-    fn record_statement_conflicts(&mut self, stmt: &Statement<'_>) {
-        match &stmt.kind {
-            // While the left and right sides of an assignment must not overlap, we do not mark
-            // conflicts here as that would make this optimization useless. When we optimize, we
-            // eliminate the resulting self-assignments automatically.
-            StatementKind::Assign(_) => {}
-
-            StatementKind::LlvmInlineAsm(asm) => {
-                // Inputs and outputs must not overlap.
-                for (_, input) in &*asm.inputs {
-                    if let Some(in_place) = input.place() {
-                        if !in_place.is_indirect() {
-                            for out_place in &*asm.outputs {
-                                if !out_place.is_indirect() && !in_place.is_indirect() {
-                                    self.record_local_conflict(
-                                        in_place.local,
-                                        out_place.local,
-                                        "aliasing llvm_asm! operands",
-                                    );
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-
-            StatementKind::SetDiscriminant { .. }
-            | StatementKind::StorageLive(..)
-            | StatementKind::StorageDead(..)
-            | StatementKind::Retag(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
-            | StatementKind::Nop => {}
-        }
-    }
-
-    fn record_terminator_conflicts(&mut self, term: &Terminator<'_>) {
-        match &term.kind {
-            TerminatorKind::DropAndReplace {
-                place: dropped_place,
-                value,
-                target: _,
-                unwind: _,
-            } => {
-                if let Some(place) = value.place() {
-                    if !place.is_indirect() && !dropped_place.is_indirect() {
-                        self.record_local_conflict(
-                            place.local,
-                            dropped_place.local,
-                            "DropAndReplace operand overlap",
-                        );
-                    }
-                }
-            }
-            TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
-                if let Some(place) = value.place() {
-                    if !place.is_indirect() && !resume_arg.is_indirect() {
-                        self.record_local_conflict(
-                            place.local,
-                            resume_arg.local,
-                            "Yield operand overlap",
-                        );
-                    }
-                }
-            }
-            TerminatorKind::Call {
-                func,
-                args,
-                destination: Some((dest_place, _)),
-                cleanup: _,
-                from_hir_call: _,
-                fn_span: _,
-            } => {
-                // No arguments may overlap with the destination.
-                for arg in args.iter().chain(Some(func)) {
-                    if let Some(place) = arg.place() {
-                        if !place.is_indirect() && !dest_place.is_indirect() {
-                            self.record_local_conflict(
-                                dest_place.local,
-                                place.local,
-                                "call dest/arg overlap",
-                            );
-                        }
-                    }
-                }
-            }
-            TerminatorKind::InlineAsm {
-                template: _,
-                operands,
-                options: _,
-                line_spans: _,
-                destination: _,
-            } => {
-                // The intended semantics here aren't documented, we just assume that nothing that
-                // could be written to by the assembly may overlap with any other operands.
-                for op in operands {
-                    match op {
-                        InlineAsmOperand::Out { reg: _, late: _, place: Some(dest_place) }
-                        | InlineAsmOperand::InOut {
-                            reg: _,
-                            late: _,
-                            in_value: _,
-                            out_place: Some(dest_place),
-                        } => {
-                            // For output place `place`, add all places accessed by the inline asm.
-                            for op in operands {
-                                match op {
-                                    InlineAsmOperand::In { reg: _, value } => {
-                                        if let Some(p) = value.place() {
-                                            if !p.is_indirect() && !dest_place.is_indirect() {
-                                                self.record_local_conflict(
-                                                    p.local,
-                                                    dest_place.local,
-                                                    "asm! operand overlap",
-                                                );
-                                            }
-                                        }
-                                    }
-                                    InlineAsmOperand::Out {
-                                        reg: _,
-                                        late: _,
-                                        place: Some(place),
-                                    } => {
-                                        if !place.is_indirect() && !dest_place.is_indirect() {
-                                            self.record_local_conflict(
-                                                place.local,
-                                                dest_place.local,
-                                                "asm! operand overlap",
-                                            );
-                                        }
-                                    }
-                                    InlineAsmOperand::InOut {
-                                        reg: _,
-                                        late: _,
-                                        in_value,
-                                        out_place,
-                                    } => {
-                                        if let Some(place) = in_value.place() {
-                                            if !place.is_indirect() && !dest_place.is_indirect() {
-                                                self.record_local_conflict(
-                                                    place.local,
-                                                    dest_place.local,
-                                                    "asm! operand overlap",
-                                                );
-                                            }
-                                        }
-
-                                        if let Some(place) = out_place {
-                                            if !place.is_indirect() && !dest_place.is_indirect() {
-                                                self.record_local_conflict(
-                                                    place.local,
-                                                    dest_place.local,
-                                                    "asm! operand overlap",
-                                                );
-                                            }
-                                        }
-                                    }
-                                    InlineAsmOperand::Out { reg: _, late: _, place: None }
-                                    | InlineAsmOperand::Const { value: _ }
-                                    | InlineAsmOperand::SymFn { value: _ }
-                                    | InlineAsmOperand::SymStatic { def_id: _ } => {}
-                                }
-                            }
-                        }
-                        InlineAsmOperand::InOut {
-                            reg: _,
-                            late: _,
-                            in_value: _,
-                            out_place: None,
-                        }
-                        | InlineAsmOperand::In { reg: _, value: _ }
-                        | InlineAsmOperand::Out { reg: _, late: _, place: None }
-                        | InlineAsmOperand::Const { value: _ }
-                        | InlineAsmOperand::SymFn { value: _ }
-                        | InlineAsmOperand::SymStatic { def_id: _ } => {}
-                    }
-                }
-            }
-
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Call { destination: None, .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {}
-        }
-    }
-
-    /// Checks whether `a` and `b` may be merged. Returns `false` if there's a conflict.
-    fn can_unify(&mut self, a: Local, b: Local) -> bool {
-        // After some locals have been unified, their conflicts are only tracked in the root key,
-        // so look that up.
-        let a = self.unified_locals.find(a).0;
-        let b = self.unified_locals.find(b).0;
-
-        if a == b {
-            // Already merged (part of the same connected component).
-            return false;
-        }
-
-        if self.matrix.contains(a, b) {
-            // Conflict (derived via dataflow, intra-statement conflicts, or inherited from another
-            // local during unification).
-            return false;
-        }
-
-        true
-    }
-
-    /// Merges the conflicts of `a` and `b`, so that each one inherits all conflicts of the other.
-    ///
-    /// `can_unify` must have returned `true` for the same locals, or this may panic or lead to
-    /// miscompiles.
-    ///
-    /// This is called when the pass makes the decision to unify `a` and `b` (or parts of `a` and
-    /// `b`) and is needed to ensure that future unification decisions take potentially newly
-    /// introduced conflicts into account.
-    ///
-    /// For an example, assume we have locals `_0`, `_1`, `_2`, and `_3`. There are these conflicts:
-    ///
-    /// * `_0` <-> `_1`
-    /// * `_1` <-> `_2`
-    /// * `_3` <-> `_0`
-    ///
-    /// We then decide to merge `_2` with `_3` since they don't conflict. Then we decide to merge
-    /// `_2` with `_0`, which also doesn't have a conflict in the above list. However `_2` is now
-    /// `_3`, which does conflict with `_0`.
-    fn unify(&mut self, a: Local, b: Local) {
-        trace!("unify({:?}, {:?})", a, b);
-
-        // Get the root local of the connected components. The root local stores the conflicts of
-        // all locals in the connected component (and *is stored* as the conflicting local of other
-        // locals).
-        let a = self.unified_locals.find(a).0;
-        let b = self.unified_locals.find(b).0;
-        assert_ne!(a, b);
-
-        trace!("roots: a={:?}, b={:?}", a, b);
-        trace!("{:?} conflicts: {:?}", a, self.matrix.iter(a).format(", "));
-        trace!("{:?} conflicts: {:?}", b, self.matrix.iter(b).format(", "));
-
-        self.unified_locals.union(a, b);
-
-        let root = self.unified_locals.find(a).0;
-        assert!(root == a || root == b);
-
-        // Make all locals that conflict with `a` also conflict with `b`, and vice versa.
-        self.unify_cache.clear();
-        for conflicts_with_a in self.matrix.iter(a) {
-            self.unify_cache.insert(conflicts_with_a);
-        }
-        for conflicts_with_b in self.matrix.iter(b) {
-            self.unify_cache.insert(conflicts_with_b);
-        }
-        for conflicts_with_a_or_b in self.unify_cache.iter() {
-            // Set both `a` and `b` for this local's row.
-            self.matrix.insert(conflicts_with_a_or_b, a);
-            self.matrix.insert(conflicts_with_a_or_b, b);
-        }
-
-        // Write the locals `a` conflicts with to `b`'s row.
-        self.matrix.union_rows(a, b);
-        // Write the locals `b` conflicts with to `a`'s row.
-        self.matrix.union_rows(b, a);
-    }
-}
-
-/// A `dest = {move} src;` statement at `loc`.
-///
-/// We want to consider merging `dest` and `src` due to this assignment.
-#[derive(Debug, Copy, Clone)]
-struct CandidateAssignment<'tcx> {
-    /// Does not contain indirection or indexing (so the only local it contains is the place base).
-    dest: Place<'tcx>,
-    src: Local,
-    loc: Location,
-}
-
-/// Scans the MIR for assignments between locals that we might want to consider merging.
-///
-/// This will filter out assignments that do not match the right form (as described in the top-level
-/// comment) and also throw out assignments that involve a local that has its address taken or is
-/// otherwise ineligible (eg. locals used as array indices are ignored because we cannot propagate
-/// arbitrary places into array indices).
-fn find_candidates<'a, 'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-) -> Vec<CandidateAssignment<'tcx>> {
-    let mut visitor = FindAssignments {
-        tcx,
-        body,
-        candidates: Vec::new(),
-        ever_borrowed_locals: ever_borrowed_locals(body),
-        locals_used_as_array_index: locals_used_as_array_index(body),
-    };
-    visitor.visit_body(body);
-    visitor.candidates
-}
-
-struct FindAssignments<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    candidates: Vec<CandidateAssignment<'tcx>>,
-    ever_borrowed_locals: BitSet<Local>,
-    locals_used_as_array_index: BitSet<Local>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        if let StatementKind::Assign(box (
-            dest,
-            Rvalue::Use(Operand::Copy(src) | Operand::Move(src)),
-        )) = &statement.kind
-        {
-            // `dest` must not have pointer indirection.
-            if dest.is_indirect() {
-                return;
-            }
-
-            // `src` must be a plain local.
-            if !src.projection.is_empty() {
-                return;
-            }
-
-            // Since we want to replace `src` with `dest`, `src` must not be required.
-            if is_local_required(src.local, self.body) {
-                return;
-            }
-
-            // Can't optimize if both locals ever have their address taken (can introduce
-            // aliasing).
-            // FIXME: This can be smarter and take `StorageDead` into account (which
-            // invalidates borrows).
-            if self.ever_borrowed_locals.contains(dest.local)
-                || self.ever_borrowed_locals.contains(src.local)
-            {
-                return;
-            }
-
-            assert_ne!(dest.local, src.local, "self-assignments are UB");
-
-            // We can't replace locals occurring in `PlaceElem::Index` for now.
-            if self.locals_used_as_array_index.contains(src.local) {
-                return;
-            }
-
-            // Handle the "subtle case" described above by rejecting any `dest` that is or
-            // projects through a union.
-            let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
-            if place_ty.ty.is_union() {
-                return;
-            }
-            for elem in dest.projection {
-                if let PlaceElem::Index(_) = elem {
-                    // `dest` contains an indexing projection.
-                    return;
-                }
-
-                place_ty = place_ty.projection_ty(self.tcx, elem);
-                if place_ty.ty.is_union() {
-                    return;
-                }
-            }
-
-            self.candidates.push(CandidateAssignment {
-                dest: *dest,
-                src: src.local,
-                loc: location,
-            });
-        }
-    }
-}
-
-/// Some locals are part of the function's interface and can not be removed.
-///
-/// Note that these locals *can* still be merged with non-required locals by removing that other
-/// local.
-fn is_local_required(local: Local, body: &Body<'_>) -> bool {
-    match body.local_kind(local) {
-        LocalKind::Arg | LocalKind::ReturnPointer => true,
-        LocalKind::Var | LocalKind::Temp => false,
-    }
-}
-
-/// Walks MIR to find all locals that have their address taken anywhere.
-fn ever_borrowed_locals(body: &Body<'_>) -> BitSet<Local> {
-    let mut visitor = BorrowCollector { locals: BitSet::new_empty(body.local_decls.len()) };
-    visitor.visit_body(body);
-    visitor.locals
-}
-
-struct BorrowCollector {
-    locals: BitSet<Local>,
-}
-
-impl<'tcx> Visitor<'tcx> for BorrowCollector {
-    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
-        self.super_rvalue(rvalue, location);
-
-        match rvalue {
-            Rvalue::AddressOf(_, borrowed_place) | Rvalue::Ref(_, _, borrowed_place) => {
-                if !borrowed_place.is_indirect() {
-                    self.locals.insert(borrowed_place.local);
-                }
-            }
-
-            Rvalue::Cast(..)
-            | Rvalue::Use(..)
-            | Rvalue::Repeat(..)
-            | Rvalue::Len(..)
-            | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
-            | Rvalue::NullaryOp(..)
-            | Rvalue::UnaryOp(..)
-            | Rvalue::Discriminant(..)
-            | Rvalue::Aggregate(..)
-            | Rvalue::ThreadLocalRef(..) => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        self.super_terminator(terminator, location);
-
-        match terminator.kind {
-            TerminatorKind::Drop { place: dropped_place, .. }
-            | TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
-                self.locals.insert(dropped_place.local);
-            }
-
-            TerminatorKind::Abort
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Return
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-        }
-    }
-}
-
-/// `PlaceElem::Index` only stores a `Local`, so we can't replace that with a full `Place`.
-///
-/// Collect locals used as indices so we don't generate candidates that are impossible to apply
-/// later.
-fn locals_used_as_array_index(body: &Body<'_>) -> BitSet<Local> {
-    let mut visitor = IndexCollector { locals: BitSet::new_empty(body.local_decls.len()) };
-    visitor.visit_body(body);
-    visitor.locals
-}
-
-struct IndexCollector {
-    locals: BitSet<Local>,
-}
-
-impl<'tcx> Visitor<'tcx> for IndexCollector {
-    fn visit_projection_elem(
-        &mut self,
-        local: Local,
-        proj_base: &[PlaceElem<'tcx>],
-        elem: PlaceElem<'tcx>,
-        context: PlaceContext,
-        location: Location,
-    ) {
-        if let PlaceElem::Index(i) = elem {
-            self.locals.insert(i);
-        }
-        self.super_projection_elem(local, proj_base, elem, context, location);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/dump_mir.rs b/compiler/rustc_mir/src/transform/dump_mir.rs
deleted file mode 100644
index 5b6edf17d06..00000000000
--- a/compiler/rustc_mir/src/transform/dump_mir.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-//! This pass just dumps MIR at a specified point.
-
-use std::borrow::Cow;
-use std::fmt;
-use std::fs::File;
-use std::io;
-
-use crate::transform::MirPass;
-use crate::util as mir_util;
-use rustc_middle::mir::Body;
-use rustc_middle::ty::TyCtxt;
-use rustc_session::config::{OutputFilenames, OutputType};
-
-pub struct Marker(pub &'static str);
-
-impl<'tcx> MirPass<'tcx> for Marker {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(self.0)
-    }
-
-    fn run_pass(&self, _tcx: TyCtxt<'tcx>, _body: &mut Body<'tcx>) {}
-}
-
-pub struct Disambiguator {
-    is_after: bool,
-}
-
-impl fmt::Display for Disambiguator {
-    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let title = if self.is_after { "after" } else { "before" };
-        write!(formatter, "{}", title)
-    }
-}
-
-pub fn on_mir_pass<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    pass_num: &dyn fmt::Display,
-    pass_name: &str,
-    body: &Body<'tcx>,
-    is_after: bool,
-) {
-    if mir_util::dump_enabled(tcx, pass_name, body.source.def_id()) {
-        mir_util::dump_mir(
-            tcx,
-            Some(pass_num),
-            pass_name,
-            &Disambiguator { is_after },
-            body,
-            |_, _| Ok(()),
-        );
-    }
-}
-
-pub fn emit_mir(tcx: TyCtxt<'_>, outputs: &OutputFilenames) -> io::Result<()> {
-    let path = outputs.path(OutputType::Mir);
-    let mut f = io::BufWriter::new(File::create(&path)?);
-    mir_util::write_mir_pretty(tcx, None, &mut f)?;
-    Ok(())
-}
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
deleted file mode 100644
index e507bcb0f81..00000000000
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ /dev/null
@@ -1,369 +0,0 @@
-use crate::{transform::MirPass, util::patch::MirPatch};
-use rustc_middle::mir::*;
-use rustc_middle::ty::{Ty, TyCtxt};
-use std::fmt::Debug;
-
-use super::simplify::simplify_cfg;
-
-/// This pass optimizes something like
-/// ```text
-/// let x: Option<()>;
-/// let y: Option<()>;
-/// match (x,y) {
-///     (Some(_), Some(_)) => {0},
-///     _ => {1}
-/// }
-/// ```
-/// into something like
-/// ```text
-/// let x: Option<()>;
-/// let y: Option<()>;
-/// let discriminant_x = // get discriminant of x
-/// let discriminant_y = // get discriminant of y
-/// if discriminant_x != discriminant_y || discriminant_x == None {1} else {0}
-/// ```
-pub struct EarlyOtherwiseBranch;
-
-impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        //  FIXME(#78496)
-        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
-            return;
-        }
-
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
-        trace!("running EarlyOtherwiseBranch on {:?}", body.source);
-        // we are only interested in this bb if the terminator is a switchInt
-        let bbs_with_switch =
-            body.basic_blocks().iter_enumerated().filter(|(_, bb)| is_switch(bb.terminator()));
-
-        let opts_to_apply: Vec<OptimizationToApply<'tcx>> = bbs_with_switch
-            .flat_map(|(bb_idx, bb)| {
-                let switch = bb.terminator();
-                let helper = Helper { body, tcx };
-                let infos = helper.go(bb, switch)?;
-                Some(OptimizationToApply { infos, basic_block_first_switch: bb_idx })
-            })
-            .collect();
-
-        let should_cleanup = !opts_to_apply.is_empty();
-
-        for opt_to_apply in opts_to_apply {
-            if !tcx.consider_optimizing(|| format!("EarlyOtherwiseBranch {:?}", &opt_to_apply)) {
-                break;
-            }
-
-            trace!("SUCCESS: found optimization possibility to apply: {:?}", &opt_to_apply);
-
-            let statements_before =
-                body.basic_blocks()[opt_to_apply.basic_block_first_switch].statements.len();
-            let end_of_block_location = Location {
-                block: opt_to_apply.basic_block_first_switch,
-                statement_index: statements_before,
-            };
-
-            let mut patch = MirPatch::new(body);
-
-            // create temp to store second discriminant in
-            let discr_type = opt_to_apply.infos[0].second_switch_info.discr_ty;
-            let discr_span = opt_to_apply.infos[0].second_switch_info.discr_source_info.span;
-            let second_discriminant_temp = patch.new_temp(discr_type, discr_span);
-
-            patch.add_statement(
-                end_of_block_location,
-                StatementKind::StorageLive(second_discriminant_temp),
-            );
-
-            // create assignment of discriminant
-            let place_of_adt_to_get_discriminant_of =
-                opt_to_apply.infos[0].second_switch_info.place_of_adt_discr_read;
-            patch.add_assign(
-                end_of_block_location,
-                Place::from(second_discriminant_temp),
-                Rvalue::Discriminant(place_of_adt_to_get_discriminant_of),
-            );
-
-            // create temp to store NotEqual comparison between the two discriminants
-            let not_equal = BinOp::Ne;
-            let not_equal_res_type = not_equal.ty(tcx, discr_type, discr_type);
-            let not_equal_temp = patch.new_temp(not_equal_res_type, discr_span);
-            patch.add_statement(end_of_block_location, StatementKind::StorageLive(not_equal_temp));
-
-            // create NotEqual comparison between the two discriminants
-            let first_descriminant_place =
-                opt_to_apply.infos[0].first_switch_info.discr_used_in_switch;
-            let not_equal_rvalue = Rvalue::BinaryOp(
-                not_equal,
-                Box::new((
-                    Operand::Copy(Place::from(second_discriminant_temp)),
-                    Operand::Copy(first_descriminant_place),
-                )),
-            );
-            patch.add_statement(
-                end_of_block_location,
-                StatementKind::Assign(Box::new((Place::from(not_equal_temp), not_equal_rvalue))),
-            );
-
-            let new_targets = opt_to_apply
-                .infos
-                .iter()
-                .flat_map(|x| x.second_switch_info.targets_with_values.iter())
-                .cloned();
-
-            let targets = SwitchTargets::new(
-                new_targets,
-                opt_to_apply.infos[0].first_switch_info.otherwise_bb,
-            );
-
-            // new block that jumps to the correct discriminant case. This block is switched to if the discriminants are equal
-            let new_switch_data = BasicBlockData::new(Some(Terminator {
-                source_info: opt_to_apply.infos[0].second_switch_info.discr_source_info,
-                kind: TerminatorKind::SwitchInt {
-                    // the first and second discriminants are equal, so just pick one
-                    discr: Operand::Copy(first_descriminant_place),
-                    switch_ty: discr_type,
-                    targets,
-                },
-            }));
-
-            let new_switch_bb = patch.new_block(new_switch_data);
-
-            // switch on the NotEqual. If true, then jump to the `otherwise` case.
-            // If false, then jump to a basic block that then jumps to the correct disciminant case
-            let true_case = opt_to_apply.infos[0].first_switch_info.otherwise_bb;
-            let false_case = new_switch_bb;
-            patch.patch_terminator(
-                opt_to_apply.basic_block_first_switch,
-                TerminatorKind::if_(
-                    tcx,
-                    Operand::Move(Place::from(not_equal_temp)),
-                    true_case,
-                    false_case,
-                ),
-            );
-
-            // generate StorageDead for the second_discriminant_temp not in use anymore
-            patch.add_statement(
-                end_of_block_location,
-                StatementKind::StorageDead(second_discriminant_temp),
-            );
-
-            // Generate a StorageDead for not_equal_temp in each of the targets, since we moved it into the switch
-            for bb in [false_case, true_case].iter() {
-                patch.add_statement(
-                    Location { block: *bb, statement_index: 0 },
-                    StatementKind::StorageDead(not_equal_temp),
-                );
-            }
-
-            patch.apply(body);
-        }
-
-        // Since this optimization adds new basic blocks and invalidates others,
-        // clean up the cfg to make it nicer for other passes
-        if should_cleanup {
-            simplify_cfg(tcx, body);
-        }
-    }
-}
-
-fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool {
-    matches!(terminator.kind, TerminatorKind::SwitchInt { .. })
-}
-
-struct Helper<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-}
-
-#[derive(Debug, Clone)]
-struct SwitchDiscriminantInfo<'tcx> {
-    /// Type of the discriminant being switched on
-    discr_ty: Ty<'tcx>,
-    /// The basic block that the otherwise branch points to
-    otherwise_bb: BasicBlock,
-    /// Target along with the value being branched from. Otherwise is not included
-    targets_with_values: Vec<(u128, BasicBlock)>,
-    discr_source_info: SourceInfo,
-    /// The place of the discriminant used in the switch
-    discr_used_in_switch: Place<'tcx>,
-    /// The place of the adt that has its discriminant read
-    place_of_adt_discr_read: Place<'tcx>,
-    /// The type of the adt that has its discriminant read
-    type_adt_matched_on: Ty<'tcx>,
-}
-
-#[derive(Debug)]
-struct OptimizationToApply<'tcx> {
-    infos: Vec<OptimizationInfo<'tcx>>,
-    /// Basic block of the original first switch
-    basic_block_first_switch: BasicBlock,
-}
-
-#[derive(Debug)]
-struct OptimizationInfo<'tcx> {
-    /// Info about the first switch and discriminant
-    first_switch_info: SwitchDiscriminantInfo<'tcx>,
-    /// Info about the second switch and discriminant
-    second_switch_info: SwitchDiscriminantInfo<'tcx>,
-}
-
-impl<'a, 'tcx> Helper<'a, 'tcx> {
-    pub fn go(
-        &self,
-        bb: &BasicBlockData<'tcx>,
-        switch: &Terminator<'tcx>,
-    ) -> Option<Vec<OptimizationInfo<'tcx>>> {
-        // try to find the statement that defines the discriminant that is used for the switch
-        let discr = self.find_switch_discriminant_info(bb, switch)?;
-
-        // go through each target, finding a discriminant read, and a switch
-        let results = discr
-            .targets_with_values
-            .iter()
-            .map(|(value, target)| self.find_discriminant_switch_pairing(&discr, *target, *value));
-
-        // if the optimization did not apply for one of the targets, then abort
-        if results.clone().any(|x| x.is_none()) || results.len() == 0 {
-            trace!("NO: not all of the targets matched the pattern for optimization");
-            return None;
-        }
-
-        Some(results.flatten().collect())
-    }
-
-    fn find_discriminant_switch_pairing(
-        &self,
-        discr_info: &SwitchDiscriminantInfo<'tcx>,
-        target: BasicBlock,
-        value: u128,
-    ) -> Option<OptimizationInfo<'tcx>> {
-        let bb = &self.body.basic_blocks()[target];
-        // find switch
-        let terminator = bb.terminator();
-        if is_switch(terminator) {
-            let this_bb_discr_info = self.find_switch_discriminant_info(bb, terminator)?;
-
-            // the types of the two adts matched on have to be equalfor this optimization to apply
-            if discr_info.type_adt_matched_on != this_bb_discr_info.type_adt_matched_on {
-                trace!(
-                    "NO: types do not match. LHS: {:?}, RHS: {:?}",
-                    discr_info.type_adt_matched_on,
-                    this_bb_discr_info.type_adt_matched_on
-                );
-                return None;
-            }
-
-            // the otherwise branch of the two switches have to point to the same bb
-            if discr_info.otherwise_bb != this_bb_discr_info.otherwise_bb {
-                trace!("NO: otherwise target is not the same");
-                return None;
-            }
-
-            // check that the value being matched on is the same. The
-            if this_bb_discr_info.targets_with_values.iter().find(|x| x.0 == value).is_none() {
-                trace!("NO: values being matched on are not the same");
-                return None;
-            }
-
-            // only allow optimization if the left and right of the tuple being matched are the same variants.
-            // so the following should not optimize
-            //  ```rust
-            // let x: Option<()>;
-            // let y: Option<()>;
-            // match (x,y) {
-            //     (Some(_), None) => {},
-            //     _ => {}
-            // }
-            //  ```
-            // We check this by seeing that the value of the first discriminant is the only other discriminant value being used as a target in the second switch
-            if !(this_bb_discr_info.targets_with_values.len() == 1
-                && this_bb_discr_info.targets_with_values[0].0 == value)
-            {
-                trace!(
-                    "NO: The second switch did not have only 1 target (besides otherwise) that had the same value as the value from the first switch that got us here"
-                );
-                return None;
-            }
-
-            // when the second place is a projection of the first one, it's not safe to calculate their discriminant values sequentially.
-            // for example, this should not be optimized:
-            //
-            // ```rust
-            // enum E<'a> { Empty, Some(&'a E<'a>), }
-            // let Some(Some(_)) = e;
-            // ```
-            //
-            // ```mir
-            // bb0: {
-            //   _2 = discriminant(*_1)
-            //   switchInt(_2) -> [...]
-            // }
-            // bb1: {
-            //   _3 = discriminant(*(((*_1) as Some).0: &E))
-            //   switchInt(_3) -> [...]
-            // }
-            // ```
-            let discr_place = discr_info.place_of_adt_discr_read;
-            let this_discr_place = this_bb_discr_info.place_of_adt_discr_read;
-            if discr_place.local == this_discr_place.local
-                && this_discr_place.projection.starts_with(discr_place.projection)
-            {
-                trace!("NO: one target is the projection of another");
-                return None;
-            }
-
-            // if we reach this point, the optimization applies, and we should be able to optimize this case
-            // store the info that is needed to apply the optimization
-
-            Some(OptimizationInfo {
-                first_switch_info: discr_info.clone(),
-                second_switch_info: this_bb_discr_info,
-            })
-        } else {
-            None
-        }
-    }
-
-    fn find_switch_discriminant_info(
-        &self,
-        bb: &BasicBlockData<'tcx>,
-        switch: &Terminator<'tcx>,
-    ) -> Option<SwitchDiscriminantInfo<'tcx>> {
-        match &switch.kind {
-            TerminatorKind::SwitchInt { discr, targets, .. } => {
-                let discr_local = discr.place()?.as_local()?;
-                // the declaration of the discriminant read. Place of this read is being used in the switch
-                let discr_decl = &self.body.local_decls()[discr_local];
-                let discr_ty = discr_decl.ty;
-                // the otherwise target lies as the last element
-                let otherwise_bb = targets.otherwise();
-                let targets_with_values = targets.iter().collect();
-
-                // find the place of the adt where the discriminant is being read from
-                // assume this is the last statement of the block
-                let place_of_adt_discr_read = match bb.statements.last()?.kind {
-                    StatementKind::Assign(box (_, Rvalue::Discriminant(adt_place))) => {
-                        Some(adt_place)
-                    }
-                    _ => None,
-                }?;
-
-                let type_adt_matched_on = place_of_adt_discr_read.ty(self.body, self.tcx).ty;
-
-                Some(SwitchDiscriminantInfo {
-                    discr_used_in_switch: discr.place()?,
-                    discr_ty,
-                    otherwise_bb,
-                    targets_with_values,
-                    discr_source_info: discr_decl.source_info,
-                    place_of_adt_discr_read,
-                    type_adt_matched_on,
-                })
-            }
-            _ => unreachable!("must only be passed terminator that is a switch"),
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs
deleted file mode 100644
index 9b44af06b7d..00000000000
--- a/compiler/rustc_mir/src/transform/elaborate_drops.rs
+++ /dev/null
@@ -1,589 +0,0 @@
-use crate::dataflow;
-use crate::dataflow::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
-use crate::dataflow::move_paths::{LookupResult, MoveData, MovePathIndex};
-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::util::elaborate_drops::{elaborate_drop, DropFlagState, Unwind};
-use crate::util::elaborate_drops::{DropElaborator, DropFlagMode, DropStyle};
-use crate::util::patch::MirPatch;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
-use rustc_span::Span;
-use rustc_target::abi::VariantIdx;
-use std::fmt;
-
-pub struct ElaborateDrops;
-
-impl<'tcx> MirPass<'tcx> for ElaborateDrops {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        debug!("elaborate_drops({:?} @ {:?})", body.source, body.span);
-
-        let def_id = body.source.def_id();
-        let param_env = tcx.param_env_reveal_all_normalized(def_id);
-        let move_data = match MoveData::gather_moves(body, tcx, param_env) {
-            Ok(move_data) => move_data,
-            Err((move_data, _)) => {
-                tcx.sess.delay_span_bug(
-                    body.span,
-                    "No `move_errors` should be allowed in MIR borrowck",
-                );
-                move_data
-            }
-        };
-        let elaborate_patch = {
-            let body = &*body;
-            let env = MoveDataParamEnv { move_data, param_env };
-            let dead_unwinds = find_dead_unwinds(tcx, body, &env);
-
-            let inits = MaybeInitializedPlaces::new(tcx, body, &env)
-                .into_engine(tcx, body)
-                .dead_unwinds(&dead_unwinds)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
-                .into_results_cursor(body);
-
-            let uninits = MaybeUninitializedPlaces::new(tcx, body, &env)
-                .mark_inactive_variants_as_uninit()
-                .into_engine(tcx, body)
-                .dead_unwinds(&dead_unwinds)
-                .pass_name("elaborate_drops")
-                .iterate_to_fixpoint()
-                .into_results_cursor(body);
-
-            ElaborateDropsCtxt {
-                tcx,
-                body,
-                env: &env,
-                init_data: InitializationData { inits, uninits },
-                drop_flags: Default::default(),
-                patch: MirPatch::new(body),
-            }
-            .elaborate()
-        };
-        elaborate_patch.apply(body);
-    }
-}
-
-/// Returns the set of basic blocks whose unwind edges are known
-/// to not be reachable, because they are `drop` terminators
-/// that can't drop anything.
-fn find_dead_unwinds<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    env: &MoveDataParamEnv<'tcx>,
-) -> BitSet<BasicBlock> {
-    debug!("find_dead_unwinds({:?})", body.span);
-    // We only need to do this pass once, because unwind edges can only
-    // reach cleanup blocks, which can't have unwind edges themselves.
-    let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
-    let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env)
-        .into_engine(tcx, body)
-        .pass_name("find_dead_unwinds")
-        .iterate_to_fixpoint()
-        .into_results_cursor(body);
-    for (bb, bb_data) in body.basic_blocks().iter_enumerated() {
-        let place = match bb_data.terminator().kind {
-            TerminatorKind::Drop { ref place, unwind: Some(_), .. }
-            | TerminatorKind::DropAndReplace { ref place, unwind: Some(_), .. } => place,
-            _ => continue,
-        };
-
-        debug!("find_dead_unwinds @ {:?}: {:?}", bb, bb_data);
-
-        let path = match env.move_data.rev_lookup.find(place.as_ref()) {
-            LookupResult::Exact(e) => e,
-            LookupResult::Parent(..) => {
-                debug!("find_dead_unwinds: has parent; skipping");
-                continue;
-            }
-        };
-
-        flow_inits.seek_before_primary_effect(body.terminator_loc(bb));
-        debug!(
-            "find_dead_unwinds @ {:?}: path({:?})={:?}; init_data={:?}",
-            bb,
-            place,
-            path,
-            flow_inits.get()
-        );
-
-        let mut maybe_live = false;
-        on_all_drop_children_bits(tcx, body, &env, path, |child| {
-            maybe_live |= flow_inits.contains(child);
-        });
-
-        debug!("find_dead_unwinds @ {:?}: maybe_live={}", bb, maybe_live);
-        if !maybe_live {
-            dead_unwinds.insert(bb);
-        }
-    }
-
-    dead_unwinds
-}
-
-struct InitializationData<'mir, 'tcx> {
-    inits: ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>,
-    uninits: ResultsCursor<'mir, 'tcx, MaybeUninitializedPlaces<'mir, 'tcx>>,
-}
-
-impl InitializationData<'_, '_> {
-    fn seek_before(&mut self, loc: Location) {
-        self.inits.seek_before_primary_effect(loc);
-        self.uninits.seek_before_primary_effect(loc);
-    }
-
-    fn maybe_live_dead(&self, path: MovePathIndex) -> (bool, bool) {
-        (self.inits.contains(path), self.uninits.contains(path))
-    }
-}
-
-struct Elaborator<'a, 'b, 'tcx> {
-    ctxt: &'a mut ElaborateDropsCtxt<'b, 'tcx>,
-}
-
-impl<'a, 'b, 'tcx> fmt::Debug for Elaborator<'a, 'b, 'tcx> {
-    fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        Ok(())
-    }
-}
-
-impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> {
-    type Path = MovePathIndex;
-
-    fn patch(&mut self) -> &mut MirPatch<'tcx> {
-        &mut self.ctxt.patch
-    }
-
-    fn body(&self) -> &'a Body<'tcx> {
-        self.ctxt.body
-    }
-
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.ctxt.tcx
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.ctxt.param_env()
-    }
-
-    fn drop_style(&self, path: Self::Path, mode: DropFlagMode) -> DropStyle {
-        let ((maybe_live, maybe_dead), multipart) = match mode {
-            DropFlagMode::Shallow => (self.ctxt.init_data.maybe_live_dead(path), false),
-            DropFlagMode::Deep => {
-                let mut some_live = false;
-                let mut some_dead = false;
-                let mut children_count = 0;
-                on_all_drop_children_bits(self.tcx(), self.body(), self.ctxt.env, path, |child| {
-                    let (live, dead) = self.ctxt.init_data.maybe_live_dead(child);
-                    debug!("elaborate_drop: state({:?}) = {:?}", child, (live, dead));
-                    some_live |= live;
-                    some_dead |= dead;
-                    children_count += 1;
-                });
-                ((some_live, some_dead), children_count != 1)
-            }
-        };
-        match (maybe_live, maybe_dead, multipart) {
-            (false, _, _) => DropStyle::Dead,
-            (true, false, _) => DropStyle::Static,
-            (true, true, false) => DropStyle::Conditional,
-            (true, true, true) => DropStyle::Open,
-        }
-    }
-
-    fn clear_drop_flag(&mut self, loc: Location, path: Self::Path, mode: DropFlagMode) {
-        match mode {
-            DropFlagMode::Shallow => {
-                self.ctxt.set_drop_flag(loc, path, DropFlagState::Absent);
-            }
-            DropFlagMode::Deep => {
-                on_all_children_bits(
-                    self.tcx(),
-                    self.body(),
-                    self.ctxt.move_data(),
-                    path,
-                    |child| self.ctxt.set_drop_flag(loc, child, DropFlagState::Absent),
-                );
-            }
-        }
-    }
-
-    fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
-            ProjectionElem::Field(idx, _) => idx == field,
-            _ => false,
-        })
-    }
-
-    fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
-            ProjectionElem::ConstantIndex { offset, min_length, from_end } => {
-                debug_assert!(size == min_length, "min_length should be exact for arrays");
-                assert!(!from_end, "from_end should not be used for array element ConstantIndex");
-                offset == index
-            }
-            _ => false,
-        })
-    }
-
-    fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| {
-            e == ProjectionElem::Deref
-        })
-    }
-
-    fn downcast_subpath(&self, path: Self::Path, variant: VariantIdx) -> Option<Self::Path> {
-        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |e| match e {
-            ProjectionElem::Downcast(_, idx) => idx == variant,
-            _ => false,
-        })
-    }
-
-    fn get_drop_flag(&mut self, path: Self::Path) -> Option<Operand<'tcx>> {
-        self.ctxt.drop_flag(path).map(Operand::Copy)
-    }
-}
-
-struct ElaborateDropsCtxt<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-    env: &'a MoveDataParamEnv<'tcx>,
-    init_data: InitializationData<'a, 'tcx>,
-    drop_flags: FxHashMap<MovePathIndex, Local>,
-    patch: MirPatch<'tcx>,
-}
-
-impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
-    fn move_data(&self) -> &'b MoveData<'tcx> {
-        &self.env.move_data
-    }
-
-    fn param_env(&self) -> ty::ParamEnv<'tcx> {
-        self.env.param_env
-    }
-
-    fn create_drop_flag(&mut self, index: MovePathIndex, span: Span) {
-        let tcx = self.tcx;
-        let patch = &mut self.patch;
-        debug!("create_drop_flag({:?})", self.body.span);
-        self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span));
-    }
-
-    fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> {
-        self.drop_flags.get(&index).map(|t| Place::from(*t))
-    }
-
-    /// create a patch that elaborates all drops in the input
-    /// MIR.
-    fn elaborate(mut self) -> MirPatch<'tcx> {
-        self.collect_drop_flags();
-
-        self.elaborate_drops();
-
-        self.drop_flags_on_init();
-        self.drop_flags_for_fn_rets();
-        self.drop_flags_for_args();
-        self.drop_flags_for_locs();
-
-        self.patch
-    }
-
-    fn collect_drop_flags(&mut self) {
-        for (bb, data) in self.body.basic_blocks().iter_enumerated() {
-            let terminator = data.terminator();
-            let place = match terminator.kind {
-                TerminatorKind::Drop { ref place, .. }
-                | TerminatorKind::DropAndReplace { ref place, .. } => place,
-                _ => continue,
-            };
-
-            self.init_data.seek_before(self.body.terminator_loc(bb));
-
-            let path = self.move_data().rev_lookup.find(place.as_ref());
-            debug!("collect_drop_flags: {:?}, place {:?} ({:?})", bb, place, path);
-
-            let path = match path {
-                LookupResult::Exact(e) => e,
-                LookupResult::Parent(None) => continue,
-                LookupResult::Parent(Some(parent)) => {
-                    let (_maybe_live, maybe_dead) = self.init_data.maybe_live_dead(parent);
-                    if maybe_dead {
-                        span_bug!(
-                            terminator.source_info.span,
-                            "drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
-                            bb,
-                            place,
-                            path
-                        );
-                    }
-                    continue;
-                }
-            };
-
-            on_all_drop_children_bits(self.tcx, self.body, self.env, path, |child| {
-                let (maybe_live, maybe_dead) = self.init_data.maybe_live_dead(child);
-                debug!(
-                    "collect_drop_flags: collecting {:?} from {:?}@{:?} - {:?}",
-                    child,
-                    place,
-                    path,
-                    (maybe_live, maybe_dead)
-                );
-                if maybe_live && maybe_dead {
-                    self.create_drop_flag(child, terminator.source_info.span)
-                }
-            });
-        }
-    }
-
-    fn elaborate_drops(&mut self) {
-        for (bb, data) in self.body.basic_blocks().iter_enumerated() {
-            let loc = Location { block: bb, statement_index: data.statements.len() };
-            let terminator = data.terminator();
-
-            let resume_block = self.patch.resume_block();
-            match terminator.kind {
-                TerminatorKind::Drop { place, target, unwind } => {
-                    self.init_data.seek_before(loc);
-                    match self.move_data().rev_lookup.find(place.as_ref()) {
-                        LookupResult::Exact(path) => elaborate_drop(
-                            &mut Elaborator { ctxt: self },
-                            terminator.source_info,
-                            place,
-                            path,
-                            target,
-                            if data.is_cleanup {
-                                Unwind::InCleanup
-                            } else {
-                                Unwind::To(Option::unwrap_or(unwind, resume_block))
-                            },
-                            bb,
-                        ),
-                        LookupResult::Parent(..) => {
-                            span_bug!(
-                                terminator.source_info.span,
-                                "drop of untracked value {:?}",
-                                bb
-                            );
-                        }
-                    }
-                }
-                TerminatorKind::DropAndReplace { place, ref value, target, unwind } => {
-                    assert!(!data.is_cleanup);
-
-                    self.elaborate_replace(loc, place, value, target, unwind);
-                }
-                _ => continue,
-            }
-        }
-    }
-
-    /// Elaborate a MIR `replace` terminator. This instruction
-    /// is not directly handled by codegen, and therefore
-    /// must be desugared.
-    ///
-    /// The desugaring drops the location if needed, and then writes
-    /// the value (including setting the drop flag) over it in *both* arms.
-    ///
-    /// The `replace` terminator can also be called on places that
-    /// are not tracked by elaboration (for example,
-    /// `replace x[i] <- tmp0`). The borrow checker requires that
-    /// these locations are initialized before the assignment,
-    /// so we just generate an unconditional drop.
-    fn elaborate_replace(
-        &mut self,
-        loc: Location,
-        place: Place<'tcx>,
-        value: &Operand<'tcx>,
-        target: BasicBlock,
-        unwind: Option<BasicBlock>,
-    ) {
-        let bb = loc.block;
-        let data = &self.body[bb];
-        let terminator = data.terminator();
-        assert!(!data.is_cleanup, "DropAndReplace in unwind path not supported");
-
-        let assign = Statement {
-            kind: StatementKind::Assign(Box::new((place, Rvalue::Use(value.clone())))),
-            source_info: terminator.source_info,
-        };
-
-        let unwind = unwind.unwrap_or_else(|| self.patch.resume_block());
-        let unwind = self.patch.new_block(BasicBlockData {
-            statements: vec![assign.clone()],
-            terminator: Some(Terminator {
-                kind: TerminatorKind::Goto { target: unwind },
-                ..*terminator
-            }),
-            is_cleanup: true,
-        });
-
-        let target = self.patch.new_block(BasicBlockData {
-            statements: vec![assign],
-            terminator: Some(Terminator { kind: TerminatorKind::Goto { target }, ..*terminator }),
-            is_cleanup: false,
-        });
-
-        match self.move_data().rev_lookup.find(place.as_ref()) {
-            LookupResult::Exact(path) => {
-                debug!("elaborate_drop_and_replace({:?}) - tracked {:?}", terminator, path);
-                self.init_data.seek_before(loc);
-                elaborate_drop(
-                    &mut Elaborator { ctxt: self },
-                    terminator.source_info,
-                    place,
-                    path,
-                    target,
-                    Unwind::To(unwind),
-                    bb,
-                );
-                on_all_children_bits(self.tcx, self.body, self.move_data(), path, |child| {
-                    self.set_drop_flag(
-                        Location { block: target, statement_index: 0 },
-                        child,
-                        DropFlagState::Present,
-                    );
-                    self.set_drop_flag(
-                        Location { block: unwind, statement_index: 0 },
-                        child,
-                        DropFlagState::Present,
-                    );
-                });
-            }
-            LookupResult::Parent(parent) => {
-                // drop and replace behind a pointer/array/whatever. The location
-                // must be initialized.
-                debug!("elaborate_drop_and_replace({:?}) - untracked {:?}", terminator, parent);
-                self.patch.patch_terminator(
-                    bb,
-                    TerminatorKind::Drop { place, target, unwind: Some(unwind) },
-                );
-            }
-        }
-    }
-
-    fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
-        Rvalue::Use(Operand::Constant(Box::new(Constant {
-            span,
-            user_ty: None,
-            literal: ty::Const::from_bool(self.tcx, val).into(),
-        })))
-    }
-
-    fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
-        if let Some(&flag) = self.drop_flags.get(&path) {
-            let span = self.patch.source_info_for_location(self.body, loc).span;
-            let val = self.constant_bool(span, val.value());
-            self.patch.add_assign(loc, Place::from(flag), val);
-        }
-    }
-
-    fn drop_flags_on_init(&mut self) {
-        let loc = Location::START;
-        let span = self.patch.source_info_for_location(self.body, loc).span;
-        let false_ = self.constant_bool(span, false);
-        for flag in self.drop_flags.values() {
-            self.patch.add_assign(loc, Place::from(*flag), false_.clone());
-        }
-    }
-
-    fn drop_flags_for_fn_rets(&mut self) {
-        for (bb, data) in self.body.basic_blocks().iter_enumerated() {
-            if let TerminatorKind::Call {
-                destination: Some((ref place, tgt)),
-                cleanup: Some(_),
-                ..
-            } = data.terminator().kind
-            {
-                assert!(!self.patch.is_patched(bb));
-
-                let loc = Location { block: tgt, statement_index: 0 };
-                let path = self.move_data().rev_lookup.find(place.as_ref());
-                on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
-                    self.set_drop_flag(loc, child, DropFlagState::Present)
-                });
-            }
-        }
-    }
-
-    fn drop_flags_for_args(&mut self) {
-        let loc = Location::START;
-        dataflow::drop_flag_effects_for_function_entry(self.tcx, self.body, self.env, |path, ds| {
-            self.set_drop_flag(loc, path, ds);
-        })
-    }
-
-    fn drop_flags_for_locs(&mut self) {
-        // We intentionally iterate only over the *old* basic blocks.
-        //
-        // Basic blocks created by drop elaboration update their
-        // drop flags by themselves, to avoid the drop flags being
-        // clobbered before they are read.
-
-        for (bb, data) in self.body.basic_blocks().iter_enumerated() {
-            debug!("drop_flags_for_locs({:?})", data);
-            for i in 0..(data.statements.len() + 1) {
-                debug!("drop_flag_for_locs: stmt {}", i);
-                let mut allow_initializations = true;
-                if i == data.statements.len() {
-                    match data.terminator().kind {
-                        TerminatorKind::Drop { .. } => {
-                            // drop elaboration should handle that by itself
-                            continue;
-                        }
-                        TerminatorKind::DropAndReplace { .. } => {
-                            // this contains the move of the source and
-                            // the initialization of the destination. We
-                            // only want the former - the latter is handled
-                            // by the elaboration code and must be done
-                            // *after* the destination is dropped.
-                            assert!(self.patch.is_patched(bb));
-                            allow_initializations = false;
-                        }
-                        TerminatorKind::Resume => {
-                            // It is possible for `Resume` to be patched
-                            // (in particular it can be patched to be replaced with
-                            // a Goto; see `MirPatch::new`).
-                        }
-                        _ => {
-                            assert!(!self.patch.is_patched(bb));
-                        }
-                    }
-                }
-                let loc = Location { block: bb, statement_index: i };
-                dataflow::drop_flag_effects_for_location(
-                    self.tcx,
-                    self.body,
-                    self.env,
-                    loc,
-                    |path, ds| {
-                        if ds == DropFlagState::Absent || allow_initializations {
-                            self.set_drop_flag(loc, path, ds)
-                        }
-                    },
-                )
-            }
-
-            // There may be a critical edge after this call,
-            // so mark the return as initialized *before* the
-            // call.
-            if let TerminatorKind::Call {
-                destination: Some((ref place, _)), cleanup: None, ..
-            } = data.terminator().kind
-            {
-                assert!(!self.patch.is_patched(bb));
-
-                let loc = Location { block: bb, statement_index: data.statements.len() };
-                let path = self.move_data().rev_lookup.find(place.as_ref());
-                on_lookup_result_bits(self.tcx, self.body, self.move_data(), path, |child| {
-                    self.set_drop_flag(loc, child, DropFlagState::Present)
-                });
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/function_item_references.rs b/compiler/rustc_mir/src/transform/function_item_references.rs
deleted file mode 100644
index ba2c91a9347..00000000000
--- a/compiler/rustc_mir/src/transform/function_item_references.rs
+++ /dev/null
@@ -1,223 +0,0 @@
-use rustc_errors::Applicability;
-use rustc_hir::def_id::DefId;
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{
-    self,
-    subst::{GenericArgKind, Subst, SubstsRef},
-    PredicateKind, Ty, TyCtxt, TyS,
-};
-use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
-use rustc_span::{symbol::sym, Span};
-use rustc_target::spec::abi::Abi;
-
-use crate::transform::MirPass;
-
-pub struct FunctionItemReferences;
-
-impl<'tcx> MirPass<'tcx> for FunctionItemReferences {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let mut checker = FunctionItemRefChecker { tcx, body };
-        checker.visit_body(&body);
-    }
-}
-
-struct FunctionItemRefChecker<'a, 'tcx> {
-    tcx: TyCtxt<'tcx>,
-    body: &'a Body<'tcx>,
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for FunctionItemRefChecker<'a, 'tcx> {
-    /// Emits a lint for function reference arguments bound by `fmt::Pointer` or passed to
-    /// `transmute`. This only handles arguments in calls outside macro expansions to avoid double
-    /// counting function references formatted as pointers by macros.
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        if let TerminatorKind::Call {
-            func,
-            args,
-            destination: _,
-            cleanup: _,
-            from_hir_call: _,
-            fn_span: _,
-        } = &terminator.kind
-        {
-            let source_info = *self.body.source_info(location);
-            // Only handle function calls outside macros
-            if !source_info.span.from_expansion() {
-                let func_ty = func.ty(self.body, self.tcx);
-                if let ty::FnDef(def_id, substs_ref) = *func_ty.kind() {
-                    // Handle calls to `transmute`
-                    if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
-                        let arg_ty = args[0].ty(self.body, self.tcx);
-                        for generic_inner_ty in arg_ty.walk(self.tcx) {
-                            if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
-                                if let Some((fn_id, fn_substs)) =
-                                    FunctionItemRefChecker::is_fn_ref(inner_ty)
-                                {
-                                    let span = self.nth_arg_span(&args, 0);
-                                    self.emit_lint(fn_id, fn_substs, source_info, span);
-                                }
-                            }
-                        }
-                    } else {
-                        self.check_bound_args(def_id, substs_ref, &args, source_info);
-                    }
-                }
-            }
-        }
-        self.super_terminator(terminator, location);
-    }
-
-    /// Emits a lint for function references formatted with `fmt::Pointer::fmt` by macros. These
-    /// cases are handled as operands instead of call terminators to avoid any dependence on
-    /// unstable, internal formatting details like whether `fmt` is called directly or not.
-    fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) {
-        let source_info = *self.body.source_info(location);
-        if source_info.span.from_expansion() {
-            let op_ty = operand.ty(self.body, self.tcx);
-            if let ty::FnDef(def_id, substs_ref) = *op_ty.kind() {
-                if self.tcx.is_diagnostic_item(sym::pointer_trait_fmt, def_id) {
-                    let param_ty = substs_ref.type_at(0);
-                    if let Some((fn_id, fn_substs)) = FunctionItemRefChecker::is_fn_ref(param_ty) {
-                        // The operand's ctxt wouldn't display the lint since it's inside a macro so
-                        // we have to use the callsite's ctxt.
-                        let callsite_ctxt = source_info.span.source_callsite().ctxt();
-                        let span = source_info.span.with_ctxt(callsite_ctxt);
-                        self.emit_lint(fn_id, fn_substs, source_info, span);
-                    }
-                }
-            }
-        }
-        self.super_operand(operand, location);
-    }
-}
-
-impl<'a, 'tcx> FunctionItemRefChecker<'a, 'tcx> {
-    /// Emits a lint for function reference arguments bound by `fmt::Pointer` in calls to the
-    /// function defined by `def_id` with the substitutions `substs_ref`.
-    fn check_bound_args(
-        &self,
-        def_id: DefId,
-        substs_ref: SubstsRef<'tcx>,
-        args: &[Operand<'tcx>],
-        source_info: SourceInfo,
-    ) {
-        let param_env = self.tcx.param_env(def_id);
-        let bounds = param_env.caller_bounds();
-        for bound in bounds {
-            if let Some(bound_ty) = self.is_pointer_trait(&bound.kind().skip_binder()) {
-                // Get the argument types as they appear in the function signature.
-                let arg_defs = self.tcx.fn_sig(def_id).skip_binder().inputs();
-                for (arg_num, arg_def) in arg_defs.iter().enumerate() {
-                    // For all types reachable from the argument type in the fn sig
-                    for generic_inner_ty in arg_def.walk(self.tcx) {
-                        if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
-                            // If the inner type matches the type bound by `Pointer`
-                            if TyS::same_type(inner_ty, bound_ty) {
-                                // Do a substitution using the parameters from the callsite
-                                let subst_ty = inner_ty.subst(self.tcx, substs_ref);
-                                if let Some((fn_id, fn_substs)) =
-                                    FunctionItemRefChecker::is_fn_ref(subst_ty)
-                                {
-                                    let span = self.nth_arg_span(args, arg_num);
-                                    self.emit_lint(fn_id, fn_substs, source_info, span);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// If the given predicate is the trait `fmt::Pointer`, returns the bound parameter type.
-    fn is_pointer_trait(&self, bound: &PredicateKind<'tcx>) -> Option<Ty<'tcx>> {
-        if let ty::PredicateKind::Trait(predicate) = bound {
-            if self.tcx.is_diagnostic_item(sym::pointer_trait, predicate.def_id()) {
-                Some(predicate.trait_ref.self_ty())
-            } else {
-                None
-            }
-        } else {
-            None
-        }
-    }
-
-    /// If a type is a reference or raw pointer to the anonymous type of a function definition,
-    /// returns that function's `DefId` and `SubstsRef`.
-    fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, SubstsRef<'tcx>)> {
-        let referent_ty = match ty.kind() {
-            ty::Ref(_, referent_ty, _) => Some(referent_ty),
-            ty::RawPtr(ty_and_mut) => Some(&ty_and_mut.ty),
-            _ => None,
-        };
-        referent_ty
-            .map(|ref_ty| {
-                if let ty::FnDef(def_id, substs_ref) = *ref_ty.kind() {
-                    Some((def_id, substs_ref))
-                } else {
-                    None
-                }
-            })
-            .unwrap_or(None)
-    }
-
-    fn nth_arg_span(&self, args: &[Operand<'tcx>], n: usize) -> Span {
-        match &args[n] {
-            Operand::Copy(place) | Operand::Move(place) => {
-                self.body.local_decls[place.local].source_info.span
-            }
-            Operand::Constant(constant) => constant.span,
-        }
-    }
-
-    fn emit_lint(
-        &self,
-        fn_id: DefId,
-        fn_substs: SubstsRef<'tcx>,
-        source_info: SourceInfo,
-        span: Span,
-    ) {
-        let lint_root = self.body.source_scopes[source_info.scope]
-            .local_data
-            .as_ref()
-            .assert_crate_local()
-            .lint_root;
-        let fn_sig = self.tcx.fn_sig(fn_id);
-        let unsafety = fn_sig.unsafety().prefix_str();
-        let abi = match fn_sig.abi() {
-            Abi::Rust => String::from(""),
-            other_abi => {
-                let mut s = String::from("extern \"");
-                s.push_str(other_abi.name());
-                s.push_str("\" ");
-                s
-            }
-        };
-        let ident = self.tcx.item_name(fn_id).to_ident_string();
-        let ty_params = fn_substs.types().map(|ty| format!("{}", ty));
-        let const_params = fn_substs.consts().map(|c| format!("{}", c));
-        let params = ty_params.chain(const_params).collect::<Vec<String>>().join(", ");
-        let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
-        let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
-        let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
-        self.tcx.struct_span_lint_hir(FUNCTION_ITEM_REFERENCES, lint_root, span, |lint| {
-            lint.build("taking a reference to a function item does not give a function pointer")
-                .span_suggestion(
-                    span,
-                    &format!("cast `{}` to obtain a function pointer", ident),
-                    format!(
-                        "{} as {}{}fn({}{}){}",
-                        if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
-                        unsafety,
-                        abi,
-                        vec!["_"; num_args].join(", "),
-                        variadic,
-                        ret,
-                    ),
-                    Applicability::Unspecified,
-                )
-                .emit();
-        });
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs
deleted file mode 100644
index acdaa5b4568..00000000000
--- a/compiler/rustc_mir/src/transform/generator.rs
+++ /dev/null
@@ -1,1500 +0,0 @@
-//! This is the implementation of the pass which transforms generators into state machines.
-//!
-//! MIR generation for generators creates a function which has a self argument which
-//! passes by value. This argument is effectively a generator type which only contains upvars and
-//! is only used for this argument inside the MIR for the generator.
-//! It is passed by value to enable upvars to be moved out of it. Drop elaboration runs on that
-//! MIR before this pass and creates drop flags for MIR locals.
-//! It will also drop the generator argument (which only consists of upvars) if any of the upvars
-//! are moved out of. This pass elaborates the drops of upvars / generator argument in the case
-//! that none of the upvars were moved out of. This is because we cannot have any drops of this
-//! generator in the MIR, since it is used to create the drop glue for the generator. We'd get
-//! infinite recursion otherwise.
-//!
-//! This pass creates the implementation for the Generator::resume function and the drop shim
-//! for the generator based on the MIR input. It converts the generator argument from Self to
-//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator
-//! struct which looks like this:
-//!     First upvars are stored
-//!     It is followed by the generator state field.
-//!     Then finally the MIR locals which are live across a suspension point are stored.
-//!
-//!     struct Generator {
-//!         upvars...,
-//!         state: u32,
-//!         mir_locals...,
-//!     }
-//!
-//! This pass computes the meaning of the state field and the MIR locals which are live
-//! across a suspension point. There are however three hardcoded generator states:
-//!     0 - Generator have not been resumed yet
-//!     1 - Generator has returned / is completed
-//!     2 - Generator has been poisoned
-//!
-//! It also rewrites `return x` and `yield y` as setting a new generator state and returning
-//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
-//! MIR locals which are live across a suspension point are moved to the generator struct
-//! with references to them being updated with references to the generator struct.
-//!
-//! The pass creates two functions which have a switch on the generator state giving
-//! the action to take.
-//!
-//! One of them is the implementation of Generator::resume.
-//! For generators with state 0 (unresumed) it starts the execution of the generator.
-//! For generators with state 1 (returned) and state 2 (poisoned) it panics.
-//! Otherwise it continues the execution from the last suspension point.
-//!
-//! The other function is the drop glue for the generator.
-//! For generators with state 0 (unresumed) it drops the upvars of the generator.
-//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
-//! Otherwise it drops all the values in scope at the last suspension point.
-
-use crate::dataflow::impls::{
-    MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
-};
-use crate::dataflow::{self, Analysis};
-use crate::transform::simplify;
-use crate::transform::MirPass;
-use crate::util::dump_mir;
-use crate::util::expand_aggregate;
-use crate::util::storage;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir as hir;
-use rustc_hir::lang_items::LangItem;
-use rustc_index::bit_set::{BitMatrix, BitSet};
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::subst::{Subst, SubstsRef};
-use rustc_middle::ty::GeneratorSubsts;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
-use rustc_target::spec::PanicStrategy;
-use std::{iter, ops};
-
-pub struct StateTransform;
-
-struct RenameLocalVisitor<'tcx> {
-    from: Local,
-    to: Local,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for RenameLocalVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
-        if *local == self.from {
-            *local = self.to;
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
-        match terminator.kind {
-            TerminatorKind::Return => {
-                // Do not replace the implicit `_0` access here, as that's not possible. The
-                // transform already handles `return` correctly.
-            }
-            _ => self.super_terminator(terminator, location),
-        }
-    }
-}
-
-struct DerefArgVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for DerefArgVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
-        assert_ne!(*local, SELF_ARG);
-    }
-
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.local == SELF_ARG {
-            replace_base(
-                place,
-                Place {
-                    local: SELF_ARG,
-                    projection: self.tcx().intern_place_elems(&[ProjectionElem::Deref]),
-                },
-                self.tcx,
-            );
-        } else {
-            self.visit_local(&mut place.local, context, location);
-
-            for elem in place.projection.iter() {
-                if let PlaceElem::Index(local) = elem {
-                    assert_ne!(local, SELF_ARG);
-                }
-            }
-        }
-    }
-}
-
-struct PinArgVisitor<'tcx> {
-    ref_gen_ty: Ty<'tcx>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for PinArgVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
-        assert_ne!(*local, SELF_ARG);
-    }
-
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        if place.local == SELF_ARG {
-            replace_base(
-                place,
-                Place {
-                    local: SELF_ARG,
-                    projection: self.tcx().intern_place_elems(&[ProjectionElem::Field(
-                        Field::new(0),
-                        self.ref_gen_ty,
-                    )]),
-                },
-                self.tcx,
-            );
-        } else {
-            self.visit_local(&mut place.local, context, location);
-
-            for elem in place.projection.iter() {
-                if let PlaceElem::Index(local) = elem {
-                    assert_ne!(local, SELF_ARG);
-                }
-            }
-        }
-    }
-}
-
-fn replace_base<'tcx>(place: &mut Place<'tcx>, new_base: Place<'tcx>, tcx: TyCtxt<'tcx>) {
-    place.local = new_base.local;
-
-    let mut new_projection = new_base.projection.to_vec();
-    new_projection.append(&mut place.projection.to_vec());
-
-    place.projection = tcx.intern_place_elems(&new_projection);
-}
-
-const SELF_ARG: Local = Local::from_u32(1);
-
-/// Generator has not been resumed yet.
-const UNRESUMED: usize = GeneratorSubsts::UNRESUMED;
-/// Generator has returned / is completed.
-const RETURNED: usize = GeneratorSubsts::RETURNED;
-/// Generator has panicked and is poisoned.
-const POISONED: usize = GeneratorSubsts::POISONED;
-
-/// A `yield` point in the generator.
-struct SuspensionPoint<'tcx> {
-    /// State discriminant used when suspending or resuming at this point.
-    state: usize,
-    /// The block to jump to after resumption.
-    resume: BasicBlock,
-    /// Where to move the resume argument after resumption.
-    resume_arg: Place<'tcx>,
-    /// Which block to jump to if the generator is dropped in this state.
-    drop: Option<BasicBlock>,
-    /// Set of locals that have live storage while at this suspension point.
-    storage_liveness: BitSet<Local>,
-}
-
-struct TransformVisitor<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    state_adt_ref: &'tcx AdtDef,
-    state_substs: SubstsRef<'tcx>,
-
-    // The type of the discriminant in the generator struct
-    discr_ty: Ty<'tcx>,
-
-    // Mapping from Local to (type of local, generator struct index)
-    // FIXME(eddyb) This should use `IndexVec<Local, Option<_>>`.
-    remap: FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
-
-    // A map from a suspension point in a block to the locals which have live storage at that point
-    storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
-
-    // A list of suspension points, generated during the transform
-    suspension_points: Vec<SuspensionPoint<'tcx>>,
-
-    // The set of locals that have no `StorageLive`/`StorageDead` annotations.
-    always_live_locals: storage::AlwaysLiveLocals,
-
-    // The original RETURN_PLACE local
-    new_ret_local: Local,
-}
-
-impl TransformVisitor<'tcx> {
-    // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single
-    // element tuple variants, so we can just write to the downcasted first field and then set the
-    // discriminant to the appropriate variant.
-    fn make_state(
-        &self,
-        idx: VariantIdx,
-        val: Operand<'tcx>,
-        source_info: SourceInfo,
-    ) -> impl Iterator<Item = Statement<'tcx>> {
-        let kind = AggregateKind::Adt(self.state_adt_ref, idx, self.state_substs, None, None);
-        assert_eq!(self.state_adt_ref.variants[idx].fields.len(), 1);
-        let ty = self
-            .tcx
-            .type_of(self.state_adt_ref.variants[idx].fields[0].did)
-            .subst(self.tcx, self.state_substs);
-        expand_aggregate(
-            Place::return_place(),
-            std::iter::once((val, ty)),
-            kind,
-            source_info,
-            self.tcx,
-        )
-    }
-
-    // Create a Place referencing a generator struct field
-    fn make_field(&self, variant_index: VariantIdx, idx: usize, ty: Ty<'tcx>) -> Place<'tcx> {
-        let self_place = Place::from(SELF_ARG);
-        let base = self.tcx.mk_place_downcast_unnamed(self_place, variant_index);
-        let mut projection = base.projection.to_vec();
-        projection.push(ProjectionElem::Field(Field::new(idx), ty));
-
-        Place { local: base.local, projection: self.tcx.intern_place_elems(&projection) }
-    }
-
-    // Create a statement which changes the discriminant
-    fn set_discr(&self, state_disc: VariantIdx, source_info: SourceInfo) -> Statement<'tcx> {
-        let self_place = Place::from(SELF_ARG);
-        Statement {
-            source_info,
-            kind: StatementKind::SetDiscriminant {
-                place: Box::new(self_place),
-                variant_index: state_disc,
-            },
-        }
-    }
-
-    // Create a statement which reads the discriminant into a temporary
-    fn get_discr(&self, body: &mut Body<'tcx>) -> (Statement<'tcx>, Place<'tcx>) {
-        let temp_decl = LocalDecl::new(self.discr_ty, body.span).internal();
-        let local_decls_len = body.local_decls.push(temp_decl);
-        let temp = Place::from(local_decls_len);
-
-        let self_place = Place::from(SELF_ARG);
-        let assign = Statement {
-            source_info: SourceInfo::outermost(body.span),
-            kind: StatementKind::Assign(Box::new((temp, Rvalue::Discriminant(self_place)))),
-        };
-        (assign, temp)
-    }
-}
-
-impl MutVisitor<'tcx> for TransformVisitor<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _: PlaceContext, _: Location) {
-        assert_eq!(self.remap.get(local), None);
-    }
-
-    fn visit_place(
-        &mut self,
-        place: &mut Place<'tcx>,
-        _context: PlaceContext,
-        _location: Location,
-    ) {
-        // Replace an Local in the remap with a generator struct access
-        if let Some(&(ty, variant_index, idx)) = self.remap.get(&place.local) {
-            replace_base(place, self.make_field(variant_index, idx, ty), self.tcx);
-        }
-    }
-
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
-        // Remove StorageLive and StorageDead statements for remapped locals
-        data.retain_statements(|s| match s.kind {
-            StatementKind::StorageLive(l) | StatementKind::StorageDead(l) => {
-                !self.remap.contains_key(&l)
-            }
-            _ => true,
-        });
-
-        let ret_val = match data.terminator().kind {
-            TerminatorKind::Return => Some((
-                VariantIdx::new(1),
-                None,
-                Operand::Move(Place::from(self.new_ret_local)),
-                None,
-            )),
-            TerminatorKind::Yield { ref value, resume, resume_arg, drop } => {
-                Some((VariantIdx::new(0), Some((resume, resume_arg)), value.clone(), drop))
-            }
-            _ => None,
-        };
-
-        if let Some((state_idx, resume, v, drop)) = ret_val {
-            let source_info = data.terminator().source_info;
-            // We must assign the value first in case it gets declared dead below
-            data.statements.extend(self.make_state(state_idx, v, source_info));
-            let state = if let Some((resume, resume_arg)) = resume {
-                // Yield
-                let state = 3 + self.suspension_points.len();
-
-                // The resume arg target location might itself be remapped if its base local is
-                // live across a yield.
-                let resume_arg =
-                    if let Some(&(ty, variant, idx)) = self.remap.get(&resume_arg.local) {
-                        self.make_field(variant, idx, ty)
-                    } else {
-                        resume_arg
-                    };
-
-                self.suspension_points.push(SuspensionPoint {
-                    state,
-                    resume,
-                    resume_arg,
-                    drop,
-                    storage_liveness: self.storage_liveness[block].clone().unwrap(),
-                });
-
-                VariantIdx::new(state)
-            } else {
-                // Return
-                VariantIdx::new(RETURNED) // state for returned
-            };
-            data.statements.push(self.set_discr(state, source_info));
-            data.terminator_mut().kind = TerminatorKind::Return;
-        }
-
-        self.super_basic_block_data(block, data);
-    }
-}
-
-fn make_generator_state_argument_indirect<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let gen_ty = body.local_decls.raw[1].ty;
-
-    let ref_gen_ty =
-        tcx.mk_ref(tcx.lifetimes.re_erased, ty::TypeAndMut { ty: gen_ty, mutbl: Mutability::Mut });
-
-    // Replace the by value generator argument
-    body.local_decls.raw[1].ty = ref_gen_ty;
-
-    // Add a deref to accesses of the generator state
-    DerefArgVisitor { tcx }.visit_body(body);
-}
-
-fn make_generator_state_argument_pinned<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let ref_gen_ty = body.local_decls.raw[1].ty;
-
-    let pin_did = tcx.require_lang_item(LangItem::Pin, Some(body.span));
-    let pin_adt_ref = tcx.adt_def(pin_did);
-    let substs = tcx.intern_substs(&[ref_gen_ty.into()]);
-    let pin_ref_gen_ty = tcx.mk_adt(pin_adt_ref, substs);
-
-    // Replace the by ref generator argument
-    body.local_decls.raw[1].ty = pin_ref_gen_ty;
-
-    // Add the Pin field access to accesses of the generator state
-    PinArgVisitor { ref_gen_ty, tcx }.visit_body(body);
-}
-
-/// Allocates a new local and replaces all references of `local` with it. Returns the new local.
-///
-/// `local` will be changed to a new local decl with type `ty`.
-///
-/// Note that the new local will be uninitialized. It is the caller's responsibility to assign some
-/// valid value to it before its first use.
-fn replace_local<'tcx>(
-    local: Local,
-    ty: Ty<'tcx>,
-    body: &mut Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-) -> Local {
-    let new_decl = LocalDecl::new(ty, body.span);
-    let new_local = body.local_decls.push(new_decl);
-    body.local_decls.swap(local, new_local);
-
-    RenameLocalVisitor { from: local, to: new_local, tcx }.visit_body(body);
-
-    new_local
-}
-
-struct LivenessInfo {
-    /// Which locals are live across any suspension point.
-    saved_locals: GeneratorSavedLocals,
-
-    /// The set of saved locals live at each suspension point.
-    live_locals_at_suspension_points: Vec<BitSet<GeneratorSavedLocal>>,
-
-    /// Parallel vec to the above with SourceInfo for each yield terminator.
-    source_info_at_suspension_points: Vec<SourceInfo>,
-
-    /// For every saved local, the set of other saved locals that are
-    /// storage-live at the same time as this local. We cannot overlap locals in
-    /// the layout which have conflicting storage.
-    storage_conflicts: BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
-
-    /// For every suspending block, the locals which are storage-live across
-    /// that suspension point.
-    storage_liveness: IndexVec<BasicBlock, Option<BitSet<Local>>>,
-}
-
-fn locals_live_across_suspend_points(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    always_live_locals: &storage::AlwaysLiveLocals,
-    movable: bool,
-) -> LivenessInfo {
-    let body_ref: &Body<'_> = &body;
-
-    // Calculate when MIR locals have live storage. This gives us an upper bound of their
-    // lifetimes.
-    let mut storage_live = MaybeStorageLive::new(always_live_locals.clone())
-        .into_engine(tcx, body_ref)
-        .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
-
-    // Calculate the MIR locals which have been previously
-    // borrowed (even if they are still active).
-    let borrowed_locals_results = MaybeBorrowedLocals::all_borrows()
-        .into_engine(tcx, body_ref)
-        .pass_name("generator")
-        .iterate_to_fixpoint();
-
-    let mut borrowed_locals_cursor =
-        dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
-
-    // Calculate the MIR locals that we actually need to keep storage around
-    // for.
-    let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
-        .into_engine(tcx, body_ref)
-        .iterate_to_fixpoint();
-    let mut requires_storage_cursor =
-        dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
-
-    // Calculate the liveness of MIR locals ignoring borrows.
-    let mut liveness = MaybeLiveLocals
-        .into_engine(tcx, body_ref)
-        .pass_name("generator")
-        .iterate_to_fixpoint()
-        .into_results_cursor(body_ref);
-
-    let mut storage_liveness_map = IndexVec::from_elem(None, body.basic_blocks());
-    let mut live_locals_at_suspension_points = Vec::new();
-    let mut source_info_at_suspension_points = Vec::new();
-    let mut live_locals_at_any_suspension_point = BitSet::new_empty(body.local_decls.len());
-
-    for (block, data) in body.basic_blocks().iter_enumerated() {
-        if let TerminatorKind::Yield { .. } = data.terminator().kind {
-            let loc = Location { block, statement_index: data.statements.len() };
-
-            liveness.seek_to_block_end(block);
-            let mut live_locals = liveness.get().clone();
-
-            if !movable {
-                // The `liveness` variable contains the liveness of MIR locals ignoring borrows.
-                // This is correct for movable generators since borrows cannot live across
-                // suspension points. However for immovable generators we need to account for
-                // borrows, so we conseratively assume that all borrowed locals are live until
-                // we find a StorageDead statement referencing the locals.
-                // To do this we just union our `liveness` result with `borrowed_locals`, which
-                // contains all the locals which has been borrowed before this suspension point.
-                // If a borrow is converted to a raw reference, we must also assume that it lives
-                // forever. Note that the final liveness is still bounded by the storage liveness
-                // of the local, which happens using the `intersect` operation below.
-                borrowed_locals_cursor.seek_before_primary_effect(loc);
-                live_locals.union(borrowed_locals_cursor.get());
-            }
-
-            // Store the storage liveness for later use so we can restore the state
-            // after a suspension point
-            storage_live.seek_before_primary_effect(loc);
-            storage_liveness_map[block] = Some(storage_live.get().clone());
-
-            // Locals live are live at this point only if they are used across
-            // suspension points (the `liveness` variable)
-            // and their storage is required (the `storage_required` variable)
-            requires_storage_cursor.seek_before_primary_effect(loc);
-            live_locals.intersect(requires_storage_cursor.get());
-
-            // The generator argument is ignored.
-            live_locals.remove(SELF_ARG);
-
-            debug!("loc = {:?}, live_locals = {:?}", loc, live_locals);
-
-            // Add the locals live at this suspension point to the set of locals which live across
-            // any suspension points
-            live_locals_at_any_suspension_point.union(&live_locals);
-
-            live_locals_at_suspension_points.push(live_locals);
-            source_info_at_suspension_points.push(data.terminator().source_info);
-        }
-    }
-
-    debug!("live_locals_anywhere = {:?}", live_locals_at_any_suspension_point);
-    let saved_locals = GeneratorSavedLocals(live_locals_at_any_suspension_point);
-
-    // Renumber our liveness_map bitsets to include only the locals we are
-    // saving.
-    let live_locals_at_suspension_points = live_locals_at_suspension_points
-        .iter()
-        .map(|live_here| saved_locals.renumber_bitset(&live_here))
-        .collect();
-
-    let storage_conflicts = compute_storage_conflicts(
-        body_ref,
-        &saved_locals,
-        always_live_locals.clone(),
-        requires_storage_results,
-    );
-
-    LivenessInfo {
-        saved_locals,
-        live_locals_at_suspension_points,
-        source_info_at_suspension_points,
-        storage_conflicts,
-        storage_liveness: storage_liveness_map,
-    }
-}
-
-/// The set of `Local`s that must be saved across yield points.
-///
-/// `GeneratorSavedLocal` is indexed in terms of the elements in this set;
-/// i.e. `GeneratorSavedLocal::new(1)` corresponds to the second local
-/// included in this set.
-struct GeneratorSavedLocals(BitSet<Local>);
-
-impl GeneratorSavedLocals {
-    /// Returns an iterator over each `GeneratorSavedLocal` along with the `Local` it corresponds
-    /// to.
-    fn iter_enumerated(&self) -> impl '_ + Iterator<Item = (GeneratorSavedLocal, Local)> {
-        self.iter().enumerate().map(|(i, l)| (GeneratorSavedLocal::from(i), l))
-    }
-
-    /// Transforms a `BitSet<Local>` that contains only locals saved across yield points to the
-    /// equivalent `BitSet<GeneratorSavedLocal>`.
-    fn renumber_bitset(&self, input: &BitSet<Local>) -> BitSet<GeneratorSavedLocal> {
-        assert!(self.superset(&input), "{:?} not a superset of {:?}", self.0, input);
-        let mut out = BitSet::new_empty(self.count());
-        for (saved_local, local) in self.iter_enumerated() {
-            if input.contains(local) {
-                out.insert(saved_local);
-            }
-        }
-        out
-    }
-
-    fn get(&self, local: Local) -> Option<GeneratorSavedLocal> {
-        if !self.contains(local) {
-            return None;
-        }
-
-        let idx = self.iter().take_while(|&l| l < local).count();
-        Some(GeneratorSavedLocal::new(idx))
-    }
-}
-
-impl ops::Deref for GeneratorSavedLocals {
-    type Target = BitSet<Local>;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-/// For every saved local, looks for which locals are StorageLive at the same
-/// time. Generates a bitset for every local of all the other locals that may be
-/// StorageLive simultaneously with that local. This is used in the layout
-/// computation; see `GeneratorLayout` for more.
-fn compute_storage_conflicts(
-    body: &'mir Body<'tcx>,
-    saved_locals: &GeneratorSavedLocals,
-    always_live_locals: storage::AlwaysLiveLocals,
-    requires_storage: dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
-) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
-    assert_eq!(body.local_decls.len(), saved_locals.domain_size());
-
-    debug!("compute_storage_conflicts({:?})", body.span);
-    debug!("always_live = {:?}", always_live_locals);
-
-    // Locals that are always live or ones that need to be stored across
-    // suspension points are not eligible for overlap.
-    let mut ineligible_locals = always_live_locals.into_inner();
-    ineligible_locals.intersect(&**saved_locals);
-
-    // Compute the storage conflicts for all eligible locals.
-    let mut visitor = StorageConflictVisitor {
-        body,
-        saved_locals: &saved_locals,
-        local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
-    };
-
-    requires_storage.visit_reachable_with(body, &mut visitor);
-
-    let local_conflicts = visitor.local_conflicts;
-
-    // Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
-    //
-    // NOTE: Today we store a full conflict bitset for every local. Technically
-    // this is twice as many bits as we need, since the relation is symmetric.
-    // However, in practice these bitsets are not usually large. The layout code
-    // also needs to keep track of how many conflicts each local has, so it's
-    // simpler to keep it this way for now.
-    let mut storage_conflicts = BitMatrix::new(saved_locals.count(), saved_locals.count());
-    for (saved_local_a, local_a) in saved_locals.iter_enumerated() {
-        if ineligible_locals.contains(local_a) {
-            // Conflicts with everything.
-            storage_conflicts.insert_all_into_row(saved_local_a);
-        } else {
-            // Keep overlap information only for stored locals.
-            for (saved_local_b, local_b) in saved_locals.iter_enumerated() {
-                if local_conflicts.contains(local_a, local_b) {
-                    storage_conflicts.insert(saved_local_a, saved_local_b);
-                }
-            }
-        }
-    }
-    storage_conflicts
-}
-
-struct StorageConflictVisitor<'mir, 'tcx, 's> {
-    body: &'mir Body<'tcx>,
-    saved_locals: &'s GeneratorSavedLocals,
-    // FIXME(tmandry): Consider using sparse bitsets here once we have good
-    // benchmarks for generators.
-    local_conflicts: BitMatrix<Local, Local>,
-}
-
-impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
-    type FlowState = BitSet<Local>;
-
-    fn visit_statement_before_primary_effect(
-        &mut self,
-        state: &Self::FlowState,
-        _statement: &'mir Statement<'tcx>,
-        loc: Location,
-    ) {
-        self.apply_state(state, loc);
-    }
-
-    fn visit_terminator_before_primary_effect(
-        &mut self,
-        state: &Self::FlowState,
-        _terminator: &'mir Terminator<'tcx>,
-        loc: Location,
-    ) {
-        self.apply_state(state, loc);
-    }
-}
-
-impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> {
-    fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
-        // Ignore unreachable blocks.
-        if self.body.basic_blocks()[loc.block].terminator().kind == TerminatorKind::Unreachable {
-            return;
-        }
-
-        let mut eligible_storage_live = flow_state.clone();
-        eligible_storage_live.intersect(&**self.saved_locals);
-
-        for local in eligible_storage_live.iter() {
-            self.local_conflicts.union_row_with(&eligible_storage_live, local);
-        }
-
-        if eligible_storage_live.count() > 1 {
-            trace!("at {:?}, eligible_storage_live={:?}", loc, eligible_storage_live);
-        }
-    }
-}
-
-/// Validates the typeck view of the generator against the actual set of types saved between
-/// yield points.
-fn sanitize_witness<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-    witness: Ty<'tcx>,
-    upvars: Vec<Ty<'tcx>>,
-    saved_locals: &GeneratorSavedLocals,
-) {
-    let did = body.source.def_id();
-    let allowed_upvars = tcx.erase_regions(upvars);
-    let allowed = match witness.kind() {
-        &ty::GeneratorWitness(s) => tcx.erase_late_bound_regions(s),
-        _ => {
-            tcx.sess.delay_span_bug(
-                body.span,
-                &format!("unexpected generator witness type {:?}", witness.kind()),
-            );
-            return;
-        }
-    };
-
-    let param_env = tcx.param_env(did);
-
-    for (local, decl) in body.local_decls.iter_enumerated() {
-        // Ignore locals which are internal or not saved between yields.
-        if !saved_locals.contains(local) || decl.internal {
-            continue;
-        }
-        let decl_ty = tcx.normalize_erasing_regions(param_env, decl.ty);
-
-        // Sanity check that typeck knows about the type of locals which are
-        // live across a suspension point
-        if !allowed.contains(&decl_ty) && !allowed_upvars.contains(&decl_ty) {
-            span_bug!(
-                body.span,
-                "Broken MIR: generator contains type {} in MIR, \
-                       but typeck only knows about {} and {:?}",
-                decl_ty,
-                allowed,
-                allowed_upvars
-            );
-        }
-    }
-}
-
-fn compute_layout<'tcx>(
-    liveness: LivenessInfo,
-    body: &mut Body<'tcx>,
-) -> (
-    FxHashMap<Local, (Ty<'tcx>, VariantIdx, usize)>,
-    GeneratorLayout<'tcx>,
-    IndexVec<BasicBlock, Option<BitSet<Local>>>,
-) {
-    let LivenessInfo {
-        saved_locals,
-        live_locals_at_suspension_points,
-        source_info_at_suspension_points,
-        storage_conflicts,
-        storage_liveness,
-    } = liveness;
-
-    // Gather live local types and their indices.
-    let mut locals = IndexVec::<GeneratorSavedLocal, _>::new();
-    let mut tys = IndexVec::<GeneratorSavedLocal, _>::new();
-    for (saved_local, local) in saved_locals.iter_enumerated() {
-        locals.push(local);
-        tys.push(body.local_decls[local].ty);
-        debug!("generator saved local {:?} => {:?}", saved_local, local);
-    }
-
-    // Leave empty variants for the UNRESUMED, RETURNED, and POISONED states.
-    // In debuginfo, these will correspond to the beginning (UNRESUMED) or end
-    // (RETURNED, POISONED) of the function.
-    const RESERVED_VARIANTS: usize = 3;
-    let body_span = body.source_scopes[OUTERMOST_SOURCE_SCOPE].span;
-    let mut variant_source_info: IndexVec<VariantIdx, SourceInfo> = [
-        SourceInfo::outermost(body_span.shrink_to_lo()),
-        SourceInfo::outermost(body_span.shrink_to_hi()),
-        SourceInfo::outermost(body_span.shrink_to_hi()),
-    ]
-    .iter()
-    .copied()
-    .collect();
-
-    // Build the generator variant field list.
-    // Create a map from local indices to generator struct indices.
-    let mut variant_fields: IndexVec<VariantIdx, IndexVec<Field, GeneratorSavedLocal>> =
-        iter::repeat(IndexVec::new()).take(RESERVED_VARIANTS).collect();
-    let mut remap = FxHashMap::default();
-    for (suspension_point_idx, live_locals) in live_locals_at_suspension_points.iter().enumerate() {
-        let variant_index = VariantIdx::from(RESERVED_VARIANTS + suspension_point_idx);
-        let mut fields = IndexVec::new();
-        for (idx, saved_local) in live_locals.iter().enumerate() {
-            fields.push(saved_local);
-            // Note that if a field is included in multiple variants, we will
-            // just use the first one here. That's fine; fields do not move
-            // around inside generators, so it doesn't matter which variant
-            // index we access them by.
-            remap.entry(locals[saved_local]).or_insert((tys[saved_local], variant_index, idx));
-        }
-        variant_fields.push(fields);
-        variant_source_info.push(source_info_at_suspension_points[suspension_point_idx]);
-    }
-    debug!("generator variant_fields = {:?}", variant_fields);
-    debug!("generator storage_conflicts = {:#?}", storage_conflicts);
-
-    let layout =
-        GeneratorLayout { field_tys: tys, variant_fields, variant_source_info, storage_conflicts };
-
-    (remap, layout, storage_liveness)
-}
-
-/// Replaces the entry point of `body` with a block that switches on the generator discriminant and
-/// dispatches to blocks according to `cases`.
-///
-/// After this function, the former entry point of the function will be bb1.
-fn insert_switch<'tcx>(
-    body: &mut Body<'tcx>,
-    cases: Vec<(usize, BasicBlock)>,
-    transform: &TransformVisitor<'tcx>,
-    default: TerminatorKind<'tcx>,
-) {
-    let default_block = insert_term_block(body, default);
-    let (assign, discr) = transform.get_discr(body);
-    let switch_targets =
-        SwitchTargets::new(cases.iter().map(|(i, bb)| ((*i) as u128, *bb)), default_block);
-    let switch = TerminatorKind::SwitchInt {
-        discr: Operand::Move(discr),
-        switch_ty: transform.discr_ty,
-        targets: switch_targets,
-    };
-
-    let source_info = SourceInfo::outermost(body.span);
-    body.basic_blocks_mut().raw.insert(
-        0,
-        BasicBlockData {
-            statements: vec![assign],
-            terminator: Some(Terminator { source_info, kind: switch }),
-            is_cleanup: false,
-        },
-    );
-
-    let blocks = body.basic_blocks_mut().iter_mut();
-
-    for target in blocks.flat_map(|b| b.terminator_mut().successors_mut()) {
-        *target = BasicBlock::new(target.index() + 1);
-    }
-}
-
-fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    use crate::shim::DropShimElaborator;
-    use crate::util::elaborate_drops::{elaborate_drop, Unwind};
-    use crate::util::patch::MirPatch;
-
-    // Note that `elaborate_drops` only drops the upvars of a generator, and
-    // this is ok because `open_drop` can only be reached within that own
-    // generator's resume function.
-
-    let def_id = body.source.def_id();
-    let param_env = tcx.param_env(def_id);
-
-    let mut elaborator = DropShimElaborator { body, patch: MirPatch::new(body), tcx, param_env };
-
-    for (block, block_data) in body.basic_blocks().iter_enumerated() {
-        let (target, unwind, source_info) = match block_data.terminator() {
-            Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
-                if let Some(local) = place.as_local() {
-                    if local == SELF_ARG {
-                        (target, unwind, source_info)
-                    } else {
-                        continue;
-                    }
-                } else {
-                    continue;
-                }
-            }
-            _ => continue,
-        };
-        let unwind = if block_data.is_cleanup {
-            Unwind::InCleanup
-        } else {
-            Unwind::To(unwind.unwrap_or_else(|| elaborator.patch.resume_block()))
-        };
-        elaborate_drop(
-            &mut elaborator,
-            *source_info,
-            Place::from(SELF_ARG),
-            (),
-            *target,
-            unwind,
-            block,
-        );
-    }
-    elaborator.patch.apply(body);
-}
-
-fn create_generator_drop_shim<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    transform: &TransformVisitor<'tcx>,
-    gen_ty: Ty<'tcx>,
-    body: &mut Body<'tcx>,
-    drop_clean: BasicBlock,
-) -> Body<'tcx> {
-    let mut body = body.clone();
-    body.arg_count = 1; // make sure the resume argument is not included here
-
-    let source_info = SourceInfo::outermost(body.span);
-
-    let mut cases = create_cases(&mut body, transform, Operation::Drop);
-
-    cases.insert(0, (UNRESUMED, drop_clean));
-
-    // The returned state and the poisoned state fall through to the default
-    // case which is just to return
-
-    insert_switch(&mut body, cases, &transform, TerminatorKind::Return);
-
-    for block in body.basic_blocks_mut() {
-        let kind = &mut block.terminator_mut().kind;
-        if let TerminatorKind::GeneratorDrop = *kind {
-            *kind = TerminatorKind::Return;
-        }
-    }
-
-    // Replace the return variable
-    body.local_decls[RETURN_PLACE] = LocalDecl::with_source_info(tcx.mk_unit(), source_info);
-
-    make_generator_state_argument_indirect(tcx, &mut body);
-
-    // Change the generator argument from &mut to *mut
-    body.local_decls[SELF_ARG] = LocalDecl::with_source_info(
-        tcx.mk_ptr(ty::TypeAndMut { ty: gen_ty, mutbl: hir::Mutability::Mut }),
-        source_info,
-    );
-    if tcx.sess.opts.debugging_opts.mir_emit_retag {
-        // Alias tracking must know we changed the type
-        body.basic_blocks_mut()[START_BLOCK].statements.insert(
-            0,
-            Statement {
-                source_info,
-                kind: StatementKind::Retag(RetagKind::Raw, Box::new(Place::from(SELF_ARG))),
-            },
-        )
-    }
-
-    // Make sure we remove dead blocks to remove
-    // unrelated code from the resume part of the function
-    simplify::remove_dead_blocks(tcx, &mut body);
-
-    dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(()));
-
-    body
-}
-
-fn insert_term_block<'tcx>(body: &mut Body<'tcx>, kind: TerminatorKind<'tcx>) -> BasicBlock {
-    let source_info = SourceInfo::outermost(body.span);
-    body.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator { source_info, kind }),
-        is_cleanup: false,
-    })
-}
-
-fn insert_panic_block<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    body: &mut Body<'tcx>,
-    message: AssertMessage<'tcx>,
-) -> BasicBlock {
-    let assert_block = BasicBlock::new(body.basic_blocks().len());
-    let term = TerminatorKind::Assert {
-        cond: Operand::Constant(Box::new(Constant {
-            span: body.span,
-            user_ty: None,
-            literal: ty::Const::from_bool(tcx, false).into(),
-        })),
-        expected: true,
-        msg: message,
-        target: assert_block,
-        cleanup: None,
-    };
-
-    let source_info = SourceInfo::outermost(body.span);
-    body.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator { source_info, kind: term }),
-        is_cleanup: false,
-    });
-
-    assert_block
-}
-
-fn can_return<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
-    // Returning from a function with an uninhabited return type is undefined behavior.
-    if tcx.conservative_is_privately_uninhabited(param_env.and(body.return_ty())) {
-        return false;
-    }
-
-    // If there's a return terminator the function may return.
-    for block in body.basic_blocks() {
-        if let TerminatorKind::Return = block.terminator().kind {
-            return true;
-        }
-    }
-
-    // Otherwise the function can't return.
-    false
-}
-
-fn can_unwind<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>) -> bool {
-    // Nothing can unwind when landing pads are off.
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
-        return false;
-    }
-
-    // Unwinds can only start at certain terminators.
-    for block in body.basic_blocks() {
-        match block.terminator().kind {
-            // These never unwind.
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::InlineAsm { .. } => {}
-
-            // Resume will *continue* unwinding, but if there's no other unwinding terminator it
-            // will never be reached.
-            TerminatorKind::Resume => {}
-
-            TerminatorKind::Yield { .. } => {
-                unreachable!("`can_unwind` called before generator transform")
-            }
-
-            // These may unwind.
-            TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::Assert { .. } => return true,
-        }
-    }
-
-    // If we didn't find an unwinding terminator, the function cannot unwind.
-    false
-}
-
-fn create_generator_resume_function<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    transform: TransformVisitor<'tcx>,
-    body: &mut Body<'tcx>,
-    can_return: bool,
-) {
-    let can_unwind = can_unwind(tcx, body);
-
-    // Poison the generator when it unwinds
-    if can_unwind {
-        let source_info = SourceInfo::outermost(body.span);
-        let poison_block = body.basic_blocks_mut().push(BasicBlockData {
-            statements: vec![transform.set_discr(VariantIdx::new(POISONED), source_info)],
-            terminator: Some(Terminator { source_info, kind: TerminatorKind::Resume }),
-            is_cleanup: true,
-        });
-
-        for (idx, block) in body.basic_blocks_mut().iter_enumerated_mut() {
-            let source_info = block.terminator().source_info;
-
-            if let TerminatorKind::Resume = block.terminator().kind {
-                // An existing `Resume` terminator is redirected to jump to our dedicated
-                // "poisoning block" above.
-                if idx != poison_block {
-                    *block.terminator_mut() = Terminator {
-                        source_info,
-                        kind: TerminatorKind::Goto { target: poison_block },
-                    };
-                }
-            } else if !block.is_cleanup {
-                // Any terminators that *can* unwind but don't have an unwind target set are also
-                // pointed at our poisoning block (unless they're part of the cleanup path).
-                if let Some(unwind @ None) = block.terminator_mut().unwind_mut() {
-                    *unwind = Some(poison_block);
-                }
-            }
-        }
-    }
-
-    let mut cases = create_cases(body, &transform, Operation::Resume);
-
-    use rustc_middle::mir::AssertKind::{ResumedAfterPanic, ResumedAfterReturn};
-
-    // Jump to the entry point on the unresumed
-    cases.insert(0, (UNRESUMED, BasicBlock::new(0)));
-
-    // Panic when resumed on the returned or poisoned state
-    let generator_kind = body.generator_kind().unwrap();
-
-    if can_unwind {
-        cases.insert(
-            1,
-            (POISONED, insert_panic_block(tcx, body, ResumedAfterPanic(generator_kind))),
-        );
-    }
-
-    if can_return {
-        cases.insert(
-            1,
-            (RETURNED, insert_panic_block(tcx, body, ResumedAfterReturn(generator_kind))),
-        );
-    }
-
-    insert_switch(body, cases, &transform, TerminatorKind::Unreachable);
-
-    make_generator_state_argument_indirect(tcx, body);
-    make_generator_state_argument_pinned(tcx, body);
-
-    // Make sure we remove dead blocks to remove
-    // unrelated code from the drop part of the function
-    simplify::remove_dead_blocks(tcx, body);
-
-    dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(()));
-}
-
-fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
-    let return_block = insert_term_block(body, TerminatorKind::Return);
-
-    let term =
-        TerminatorKind::Drop { place: Place::from(SELF_ARG), target: return_block, unwind: None };
-    let source_info = SourceInfo::outermost(body.span);
-
-    // Create a block to destroy an unresumed generators. This can only destroy upvars.
-    body.basic_blocks_mut().push(BasicBlockData {
-        statements: Vec::new(),
-        terminator: Some(Terminator { source_info, kind: term }),
-        is_cleanup: false,
-    })
-}
-
-/// An operation that can be performed on a generator.
-#[derive(PartialEq, Copy, Clone)]
-enum Operation {
-    Resume,
-    Drop,
-}
-
-impl Operation {
-    fn target_block(self, point: &SuspensionPoint<'_>) -> Option<BasicBlock> {
-        match self {
-            Operation::Resume => Some(point.resume),
-            Operation::Drop => point.drop,
-        }
-    }
-}
-
-fn create_cases<'tcx>(
-    body: &mut Body<'tcx>,
-    transform: &TransformVisitor<'tcx>,
-    operation: Operation,
-) -> Vec<(usize, BasicBlock)> {
-    let source_info = SourceInfo::outermost(body.span);
-
-    transform
-        .suspension_points
-        .iter()
-        .filter_map(|point| {
-            // Find the target for this suspension point, if applicable
-            operation.target_block(point).map(|target| {
-                let mut statements = Vec::new();
-
-                // Create StorageLive instructions for locals with live storage
-                for i in 0..(body.local_decls.len()) {
-                    if i == 2 {
-                        // The resume argument is live on function entry. Don't insert a
-                        // `StorageLive`, or the following `Assign` will read from uninitialized
-                        // memory.
-                        continue;
-                    }
-
-                    let l = Local::new(i);
-                    let needs_storage_live = point.storage_liveness.contains(l)
-                        && !transform.remap.contains_key(&l)
-                        && !transform.always_live_locals.contains(l);
-                    if needs_storage_live {
-                        statements
-                            .push(Statement { source_info, kind: StatementKind::StorageLive(l) });
-                    }
-                }
-
-                if operation == Operation::Resume {
-                    // Move the resume argument to the destination place of the `Yield` terminator
-                    let resume_arg = Local::new(2); // 0 = return, 1 = self
-                    statements.push(Statement {
-                        source_info,
-                        kind: StatementKind::Assign(Box::new((
-                            point.resume_arg,
-                            Rvalue::Use(Operand::Move(resume_arg.into())),
-                        ))),
-                    });
-                }
-
-                // Then jump to the real target
-                let block = body.basic_blocks_mut().push(BasicBlockData {
-                    statements,
-                    terminator: Some(Terminator {
-                        source_info,
-                        kind: TerminatorKind::Goto { target },
-                    }),
-                    is_cleanup: false,
-                });
-
-                (point.state, block)
-            })
-        })
-        .collect()
-}
-
-impl<'tcx> MirPass<'tcx> for StateTransform {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let yield_ty = if let Some(yield_ty) = body.yield_ty() {
-            yield_ty
-        } else {
-            // This only applies to generators
-            return;
-        };
-
-        assert!(body.generator_drop().is_none());
-
-        // The first argument is the generator type passed by value
-        let gen_ty = body.local_decls.raw[1].ty;
-
-        // Get the interior types and substs which typeck computed
-        let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() {
-            ty::Generator(_, substs, movability) => {
-                let substs = substs.as_generator();
-                (
-                    substs.upvar_tys().collect(),
-                    substs.witness(),
-                    substs.discr_ty(tcx),
-                    movability == hir::Movability::Movable,
-                )
-            }
-            _ => {
-                tcx.sess
-                    .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty));
-                return;
-            }
-        };
-
-        // Compute GeneratorState<yield_ty, return_ty>
-        let state_did = tcx.require_lang_item(LangItem::GeneratorState, None);
-        let state_adt_ref = tcx.adt_def(state_did);
-        let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]);
-        let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
-
-        // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local
-        // RETURN_PLACE then is a fresh unused local with type ret_ty.
-        let new_ret_local = replace_local(RETURN_PLACE, ret_ty, body, tcx);
-
-        // We also replace the resume argument and insert an `Assign`.
-        // This is needed because the resume argument `_2` might be live across a `yield`, in which
-        // case there is no `Assign` to it that the transform can turn into a store to the generator
-        // state. After the yield the slot in the generator state would then be uninitialized.
-        let resume_local = Local::new(2);
-        let new_resume_local =
-            replace_local(resume_local, body.local_decls[resume_local].ty, body, tcx);
-
-        // When first entering the generator, move the resume argument into its new local.
-        let source_info = SourceInfo::outermost(body.span);
-        let stmts = &mut body.basic_blocks_mut()[BasicBlock::new(0)].statements;
-        stmts.insert(
-            0,
-            Statement {
-                source_info,
-                kind: StatementKind::Assign(Box::new((
-                    new_resume_local.into(),
-                    Rvalue::Use(Operand::Move(resume_local.into())),
-                ))),
-            },
-        );
-
-        let always_live_locals = storage::AlwaysLiveLocals::new(&body);
-
-        let liveness_info =
-            locals_live_across_suspend_points(tcx, body, &always_live_locals, movable);
-
-        sanitize_witness(tcx, body, interior, upvars, &liveness_info.saved_locals);
-
-        if tcx.sess.opts.debugging_opts.validate_mir {
-            let mut vis = EnsureGeneratorFieldAssignmentsNeverAlias {
-                assigned_local: None,
-                saved_locals: &liveness_info.saved_locals,
-                storage_conflicts: &liveness_info.storage_conflicts,
-            };
-
-            vis.visit_body(body);
-        }
-
-        // Extract locals which are live across suspension point into `layout`
-        // `remap` gives a mapping from local indices onto generator struct indices
-        // `storage_liveness` tells us which locals have live storage at suspension points
-        let (remap, layout, storage_liveness) = compute_layout(liveness_info, body);
-
-        let can_return = can_return(tcx, body, tcx.param_env(body.source.def_id()));
-
-        // Run the transformation which converts Places from Local to generator struct
-        // accesses for locals in `remap`.
-        // It also rewrites `return x` and `yield y` as writing a new generator state and returning
-        // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively.
-        let mut transform = TransformVisitor {
-            tcx,
-            state_adt_ref,
-            state_substs,
-            remap,
-            storage_liveness,
-            always_live_locals,
-            suspension_points: Vec::new(),
-            new_ret_local,
-            discr_ty,
-        };
-        transform.visit_body(body);
-
-        // Update our MIR struct to reflect the changes we've made
-        body.arg_count = 2; // self, resume arg
-        body.spread_arg = None;
-
-        body.generator.as_mut().unwrap().yield_ty = None;
-        body.generator.as_mut().unwrap().generator_layout = Some(layout);
-
-        // Insert `drop(generator_struct)` which is used to drop upvars for generators in
-        // the unresumed state.
-        // This is expanded to a drop ladder in `elaborate_generator_drops`.
-        let drop_clean = insert_clean_drop(body);
-
-        dump_mir(tcx, None, "generator_pre-elab", &0, body, |_, _| Ok(()));
-
-        // Expand `drop(generator_struct)` to a drop ladder which destroys upvars.
-        // If any upvars are moved out of, drop elaboration will handle upvar destruction.
-        // However we need to also elaborate the code generated by `insert_clean_drop`.
-        elaborate_generator_drops(tcx, body);
-
-        dump_mir(tcx, None, "generator_post-transform", &0, body, |_, _| Ok(()));
-
-        // Create a copy of our MIR and use it to create the drop shim for the generator
-        let drop_shim = create_generator_drop_shim(tcx, &transform, gen_ty, body, drop_clean);
-
-        body.generator.as_mut().unwrap().generator_drop = Some(drop_shim);
-
-        // Create the Generator::resume function
-        create_generator_resume_function(tcx, transform, body, can_return);
-    }
-}
-
-/// Looks for any assignments between locals (e.g., `_4 = _5`) that will both be converted to fields
-/// in the generator state machine but whose storage is not marked as conflicting
-///
-/// Validation needs to happen immediately *before* `TransformVisitor` is invoked, not after.
-///
-/// This condition would arise when the assignment is the last use of `_5` but the initial
-/// definition of `_4` if we weren't extra careful to mark all locals used inside a statement as
-/// conflicting. Non-conflicting generator saved locals may be stored at the same location within
-/// the generator state machine, which would result in ill-formed MIR: the left-hand and right-hand
-/// sides of an assignment may not alias. This caused a miscompilation in [#73137].
-///
-/// [#73137]: https://github.com/rust-lang/rust/issues/73137
-struct EnsureGeneratorFieldAssignmentsNeverAlias<'a> {
-    saved_locals: &'a GeneratorSavedLocals,
-    storage_conflicts: &'a BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal>,
-    assigned_local: Option<GeneratorSavedLocal>,
-}
-
-impl EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
-    fn saved_local_for_direct_place(&self, place: Place<'_>) -> Option<GeneratorSavedLocal> {
-        if place.is_indirect() {
-            return None;
-        }
-
-        self.saved_locals.get(place.local)
-    }
-
-    fn check_assigned_place(&mut self, place: Place<'tcx>, f: impl FnOnce(&mut Self)) {
-        if let Some(assigned_local) = self.saved_local_for_direct_place(place) {
-            assert!(self.assigned_local.is_none(), "`check_assigned_place` must not recurse");
-
-            self.assigned_local = Some(assigned_local);
-            f(self);
-            self.assigned_local = None;
-        }
-    }
-}
-
-impl Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
-    fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
-        let lhs = match self.assigned_local {
-            Some(l) => l,
-            None => {
-                // This visitor only invokes `visit_place` for the right-hand side of an assignment
-                // and only after setting `self.assigned_local`. However, the default impl of
-                // `Visitor::super_body` may call `visit_place` with a `NonUseContext` for places
-                // with debuginfo. Ignore them here.
-                assert!(!context.is_use());
-                return;
-            }
-        };
-
-        let rhs = match self.saved_local_for_direct_place(*place) {
-            Some(l) => l,
-            None => return,
-        };
-
-        if !self.storage_conflicts.contains(lhs, rhs) {
-            bug!(
-                "Assignment between generator saved locals whose storage is not \
-                    marked as conflicting: {:?}: {:?} = {:?}",
-                location,
-                lhs,
-                rhs,
-            );
-        }
-    }
-
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        match &statement.kind {
-            StatementKind::Assign(box (lhs, rhs)) => {
-                self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
-            }
-
-            // FIXME: Does `llvm_asm!` have any aliasing requirements?
-            StatementKind::LlvmInlineAsm(_) => {}
-
-            StatementKind::FakeRead(..)
-            | StatementKind::SetDiscriminant { .. }
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::Retag(..)
-            | StatementKind::AscribeUserType(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::CopyNonOverlapping(..)
-            | StatementKind::Nop => {}
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) {
-        // Checking for aliasing in terminators is probably overkill, but until we have actual
-        // semantics, we should be conservative here.
-        match &terminator.kind {
-            TerminatorKind::Call {
-                func,
-                args,
-                destination: Some((dest, _)),
-                cleanup: _,
-                from_hir_call: _,
-                fn_span: _,
-            } => {
-                self.check_assigned_place(*dest, |this| {
-                    this.visit_operand(func, location);
-                    for arg in args {
-                        this.visit_operand(arg, location);
-                    }
-                });
-            }
-
-            TerminatorKind::Yield { value, resume: _, resume_arg, drop: _ } => {
-                self.check_assigned_place(*resume_arg, |this| this.visit_operand(value, location));
-            }
-
-            // FIXME: Does `asm!` have any aliasing requirements?
-            TerminatorKind::InlineAsm { .. } => {}
-
-            TerminatorKind::Call { .. }
-            | TerminatorKind::Goto { .. }
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {}
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs
deleted file mode 100644
index 8e9da31eba1..00000000000
--- a/compiler/rustc_mir/src/transform/inline.rs
+++ /dev/null
@@ -1,966 +0,0 @@
-//! Inlining pass for MIR functions
-
-use rustc_attr::InlineAttr;
-use rustc_hir as hir;
-use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
-use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
-use rustc_middle::mir::visit::*;
-use rustc_middle::mir::*;
-use rustc_middle::ty::subst::Subst;
-use rustc_middle::ty::{self, ConstKind, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
-use rustc_span::{hygiene::ExpnKind, ExpnData, Span};
-use rustc_target::spec::abi::Abi;
-
-use super::simplify::{remove_dead_blocks, CfgSimplifier};
-use crate::transform::MirPass;
-use std::iter;
-use std::ops::{Range, RangeFrom};
-
-crate mod cycle;
-
-const INSTR_COST: usize = 5;
-const CALL_PENALTY: usize = 25;
-const LANDINGPAD_PENALTY: usize = 50;
-const RESUME_PENALTY: usize = 45;
-
-const UNKNOWN_SIZE_COST: usize = 10;
-
-pub struct Inline;
-
-#[derive(Copy, Clone, Debug)]
-struct CallSite<'tcx> {
-    callee: Instance<'tcx>,
-    fn_sig: ty::PolyFnSig<'tcx>,
-    block: BasicBlock,
-    target: Option<BasicBlock>,
-    source_info: SourceInfo,
-}
-
-/// Returns true if MIR inlining is enabled in the current compilation session.
-crate fn is_enabled(tcx: TyCtxt<'_>) -> bool {
-    if let Some(enabled) = tcx.sess.opts.debugging_opts.inline_mir {
-        return enabled;
-    }
-
-    tcx.sess.mir_opt_level() >= 3
-}
-
-impl<'tcx> MirPass<'tcx> for Inline {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if !is_enabled(tcx) {
-            return;
-        }
-
-        let span = trace_span!("inline", body = %tcx.def_path_str(body.source.def_id()));
-        let _guard = span.enter();
-        if inline(tcx, body) {
-            debug!("running simplify cfg on {:?}", body.source);
-            CfgSimplifier::new(body).simplify();
-            remove_dead_blocks(tcx, body);
-        }
-    }
-}
-
-fn inline(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
-    let def_id = body.source.def_id();
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-
-    // Only do inlining into fn bodies.
-    if !tcx.hir().body_owner_kind(hir_id).is_fn_or_closure() {
-        return false;
-    }
-    if body.source.promoted.is_some() {
-        return false;
-    }
-
-    let mut this = 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()),
-        hir_id,
-        history: Vec::new(),
-        changed: false,
-    };
-    let blocks = BasicBlock::new(0)..body.basic_blocks().next_index();
-    this.process_blocks(body, blocks);
-    this.changed
-}
-
-struct Inliner<'tcx> {
-    tcx: TyCtxt<'tcx>,
-    param_env: ParamEnv<'tcx>,
-    /// Caller codegen attributes.
-    codegen_fn_attrs: &'tcx CodegenFnAttrs,
-    /// Caller HirID.
-    hir_id: hir::HirId,
-    /// Stack of inlined Instances.
-    history: Vec<ty::Instance<'tcx>>,
-    /// Indicates that the caller body has been modified.
-    changed: bool,
-}
-
-impl Inliner<'tcx> {
-    fn process_blocks(&mut self, caller_body: &mut Body<'tcx>, blocks: Range<BasicBlock>) {
-        for bb in blocks {
-            let bb_data = &caller_body[bb];
-            if bb_data.is_cleanup {
-                continue;
-            }
-
-            let callsite = match self.resolve_callsite(caller_body, bb, bb_data) {
-                None => continue,
-                Some(it) => it,
-            };
-
-            let span = trace_span!("process_blocks", %callsite.callee, ?bb);
-            let _guard = span.enter();
-
-            match self.try_inlining(caller_body, &callsite) {
-                Err(reason) => {
-                    debug!("not-inlined {} [{}]", callsite.callee, reason);
-                    continue;
-                }
-                Ok(new_blocks) => {
-                    debug!("inlined {}", callsite.callee);
-                    self.changed = true;
-                    self.history.push(callsite.callee);
-                    self.process_blocks(caller_body, new_blocks);
-                    self.history.pop();
-                }
-            }
-        }
-    }
-
-    /// Attempts to inline a callsite into the caller body. When successful returns basic blocks
-    /// containing the inlined body. Otherwise returns an error describing why inlining didn't take
-    /// place.
-    fn try_inlining(
-        &self,
-        caller_body: &mut Body<'tcx>,
-        callsite: &CallSite<'tcx>,
-    ) -> Result<std::ops::Range<BasicBlock>, &'static str> {
-        let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
-        self.check_codegen_attributes(callsite, callee_attrs)?;
-        self.check_mir_is_available(caller_body, &callsite.callee)?;
-        let callee_body = self.tcx.instance_mir(callsite.callee.def);
-        self.check_mir_body(callsite, callee_body, callee_attrs)?;
-
-        if !self.tcx.consider_optimizing(|| {
-            format!("Inline {:?} into {}", callee_body.span, callsite.callee)
-        }) {
-            return Err("optimization fuel exhausted");
-        }
-
-        let callee_body = callsite.callee.subst_mir_and_normalize_erasing_regions(
-            self.tcx,
-            self.param_env,
-            callee_body.clone(),
-        );
-
-        let old_blocks = caller_body.basic_blocks().next_index();
-        self.inline_call(caller_body, &callsite, callee_body);
-        let new_blocks = old_blocks..caller_body.basic_blocks().next_index();
-
-        Ok(new_blocks)
-    }
-
-    fn check_mir_is_available(
-        &self,
-        caller_body: &Body<'tcx>,
-        callee: &Instance<'tcx>,
-    ) -> Result<(), &'static str> {
-        if callee.def_id() == caller_body.source.def_id() {
-            return Err("self-recursion");
-        }
-
-        match callee.def {
-            InstanceDef::Item(_) => {
-                // If there is no MIR available (either because it was not in metadata or
-                // because it has no MIR because it's an extern function), then the inliner
-                // won't cause cycles on this.
-                if !self.tcx.is_mir_available(callee.def_id()) {
-                    return Err("item MIR unavailable");
-                }
-            }
-            // These have no own callable MIR.
-            InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => {
-                return Err("instance without MIR (intrinsic / virtual)");
-            }
-            // This cannot result in an immediate cycle since the callee MIR is a shim, which does
-            // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we
-            // do not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            InstanceDef::VtableShim(_)
-            | InstanceDef::ReifyShim(_)
-            | InstanceDef::FnPtrShim(..)
-            | InstanceDef::ClosureOnceShim { .. }
-            | InstanceDef::DropGlue(..)
-            | InstanceDef::CloneShim(..) => return Ok(()),
-        }
-
-        if self.tcx.is_constructor(callee.def_id()) {
-            trace!("constructors always have MIR");
-            // Constructor functions cannot cause a query cycle.
-            return Ok(());
-        }
-
-        if let Some(callee_def_id) = callee.def_id().as_local() {
-            let callee_hir_id = self.tcx.hir().local_def_id_to_hir_id(callee_def_id);
-            // Avoid inlining into generators,
-            // since their `optimized_mir` is used for layout computation, which can
-            // create a cycle, even when no attempt is made to inline the function
-            // in the other direction.
-            if caller_body.generator.is_some() {
-                return Err("local generator (query cycle avoidance)");
-            }
-
-            // Avoid a cycle here by only using `instance_mir` only if we have
-            // a lower `HirId` than the callee. This ensures that the callee will
-            // not inline us. This trick only works without incremental compilation.
-            // So don't do it if that is enabled.
-            if !self.tcx.dep_graph.is_fully_enabled() && self.hir_id < callee_hir_id {
-                return Ok(());
-            }
-
-            // If we know for sure that the function we're calling will itself try to
-            // call us, then we avoid inlining that function.
-            if self
-                .tcx
-                .mir_callgraph_reachable((*callee, caller_body.source.def_id().expect_local()))
-            {
-                return Err("caller might be reachable from callee (query cycle avoidance)");
-            }
-
-            Ok(())
-        } else {
-            // This cannot result in an immediate cycle since the callee MIR is from another crate
-            // and is already optimized. Any subsequent inlining may cause cycles, but we do
-            // not need to catch this here, we can wait until the inliner decides to continue
-            // inlining a second time.
-            trace!("functions from other crates always have MIR");
-            Ok(())
-        }
-    }
-
-    fn resolve_callsite(
-        &self,
-        caller_body: &Body<'tcx>,
-        bb: BasicBlock,
-        bb_data: &BasicBlockData<'tcx>,
-    ) -> Option<CallSite<'tcx>> {
-        // Only consider direct calls to functions
-        let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { ref func, ref destination, .. } = terminator.kind {
-            let func_ty = func.ty(caller_body, self.tcx);
-            if let ty::FnDef(def_id, substs) = *func_ty.kind() {
-                // To resolve an instance its substs have to be fully normalized.
-                let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
-                let callee =
-                    Instance::resolve(self.tcx, self.param_env, def_id, substs).ok().flatten()?;
-
-                if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def {
-                    return None;
-                }
-
-                let fn_sig = self.tcx.fn_sig(def_id).subst(self.tcx, substs);
-
-                return Some(CallSite {
-                    callee,
-                    fn_sig,
-                    block: bb,
-                    target: destination.map(|(_, target)| target),
-                    source_info: terminator.source_info,
-                });
-            }
-        }
-
-        None
-    }
-
-    /// Returns an error if inlining is not possible based on codegen attributes alone. A success
-    /// indicates that inlining decision should be based on other criteria.
-    fn check_codegen_attributes(
-        &self,
-        callsite: &CallSite<'tcx>,
-        callee_attrs: &CodegenFnAttrs,
-    ) -> Result<(), &'static str> {
-        if let InlineAttr::Never = callee_attrs.inline {
-            return Err("never inline hint");
-        }
-
-        // Only inline local functions if they would be eligible for cross-crate
-        // inlining. This is to ensure that the final crate doesn't have MIR that
-        // reference unexported symbols
-        if callsite.callee.def_id().is_local() {
-            let is_generic = callsite.callee.substs.non_erasable_generics().next().is_some();
-            if !is_generic && !callee_attrs.requests_inline() {
-                return Err("not exported");
-            }
-        }
-
-        if callsite.fn_sig.c_variadic() {
-            return Err("C variadic");
-        }
-
-        if callee_attrs.flags.contains(CodegenFnAttrFlags::NAKED) {
-            return Err("naked");
-        }
-
-        if callee_attrs.flags.contains(CodegenFnAttrFlags::COLD) {
-            return Err("cold");
-        }
-
-        if callee_attrs.no_sanitize != self.codegen_fn_attrs.no_sanitize {
-            return Err("incompatible sanitizer set");
-        }
-
-        if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set {
-            return Err("incompatible instruction set");
-        }
-
-        for feature in &callee_attrs.target_features {
-            if !self.codegen_fn_attrs.target_features.contains(feature) {
-                return Err("incompatible target feature");
-            }
-        }
-
-        Ok(())
-    }
-
-    /// Returns inlining decision that is based on the examination of callee MIR body.
-    /// Assumes that codegen attributes have been checked for compatibility already.
-    #[instrument(level = "debug", skip(self, callee_body))]
-    fn check_mir_body(
-        &self,
-        callsite: &CallSite<'tcx>,
-        callee_body: &Body<'tcx>,
-        callee_attrs: &CodegenFnAttrs,
-    ) -> Result<(), &'static str> {
-        let tcx = self.tcx;
-
-        let mut threshold = if callee_attrs.requests_inline() {
-            self.tcx.sess.opts.debugging_opts.inline_mir_hint_threshold.unwrap_or(100)
-        } else {
-            self.tcx.sess.opts.debugging_opts.inline_mir_threshold.unwrap_or(50)
-        };
-
-        // Give a bonus functions with a small number of blocks,
-        // We normally have two or three blocks for even
-        // very small functions.
-        if callee_body.basic_blocks().len() <= 3 {
-            threshold += threshold / 4;
-        }
-        debug!("    final inline threshold = {}", threshold);
-
-        // FIXME: Give a bonus to functions with only a single caller
-        let mut first_block = true;
-        let mut cost = 0;
-
-        // Traverse the MIR manually so we can account for the effects of
-        // inlining on the CFG.
-        let mut work_list = vec![START_BLOCK];
-        let mut visited = BitSet::new_empty(callee_body.basic_blocks().len());
-        while let Some(bb) = work_list.pop() {
-            if !visited.insert(bb.index()) {
-                continue;
-            }
-            let blk = &callee_body.basic_blocks()[bb];
-
-            for stmt in &blk.statements {
-                // Don't count StorageLive/StorageDead in the inlining cost.
-                match stmt.kind {
-                    StatementKind::StorageLive(_)
-                    | StatementKind::StorageDead(_)
-                    | StatementKind::Nop => {}
-                    _ => cost += INSTR_COST,
-                }
-            }
-            let term = blk.terminator();
-            let mut is_drop = false;
-            match term.kind {
-                TerminatorKind::Drop { ref place, target, unwind }
-                | TerminatorKind::DropAndReplace { ref place, target, unwind, .. } => {
-                    is_drop = true;
-                    work_list.push(target);
-                    // If the place doesn't actually need dropping, treat it like
-                    // a regular goto.
-                    let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
-                    if ty.needs_drop(tcx, self.param_env) {
-                        cost += CALL_PENALTY;
-                        if let Some(unwind) = unwind {
-                            cost += LANDINGPAD_PENALTY;
-                            work_list.push(unwind);
-                        }
-                    } else {
-                        cost += INSTR_COST;
-                    }
-                }
-
-                TerminatorKind::Unreachable | TerminatorKind::Call { destination: None, .. }
-                    if first_block =>
-                {
-                    // If the function always diverges, don't inline
-                    // unless the cost is zero
-                    threshold = 0;
-                }
-
-                TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => {
-                    if let ty::FnDef(def_id, substs) =
-                        *callsite.callee.subst_mir(self.tcx, &f.literal.ty()).kind()
-                    {
-                        let substs = self.tcx.normalize_erasing_regions(self.param_env, substs);
-                        if let Ok(Some(instance)) =
-                            Instance::resolve(self.tcx, self.param_env, def_id, substs)
-                        {
-                            if callsite.callee.def_id() == instance.def_id() {
-                                return Err("self-recursion");
-                            } else if self.history.contains(&instance) {
-                                return Err("already inlined");
-                            }
-                        }
-                        // Don't give intrinsics the extra penalty for calls
-                        let f = tcx.fn_sig(def_id);
-                        if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic {
-                            cost += INSTR_COST;
-                        } else {
-                            cost += CALL_PENALTY;
-                        }
-                    } else {
-                        cost += CALL_PENALTY;
-                    }
-                    if cleanup.is_some() {
-                        cost += LANDINGPAD_PENALTY;
-                    }
-                }
-                TerminatorKind::Assert { cleanup, .. } => {
-                    cost += CALL_PENALTY;
-
-                    if cleanup.is_some() {
-                        cost += LANDINGPAD_PENALTY;
-                    }
-                }
-                TerminatorKind::Resume => cost += RESUME_PENALTY,
-                _ => cost += INSTR_COST,
-            }
-
-            if !is_drop {
-                for &succ in term.successors() {
-                    work_list.push(succ);
-                }
-            }
-
-            first_block = false;
-        }
-
-        // Count up the cost of local variables and temps, if we know the size
-        // use that, otherwise we use a moderately-large dummy cost.
-
-        let ptr_size = tcx.data_layout.pointer_size.bytes();
-
-        for v in callee_body.vars_and_temps_iter() {
-            let ty = callsite.callee.subst_mir(self.tcx, &callee_body.local_decls[v].ty);
-            // Cost of the var is the size in machine-words, if we know
-            // it.
-            if let Some(size) = type_size_of(tcx, self.param_env, ty) {
-                cost += ((size + ptr_size - 1) / ptr_size) as usize;
-            } else {
-                cost += UNKNOWN_SIZE_COST;
-            }
-        }
-
-        if let InlineAttr::Always = callee_attrs.inline {
-            debug!("INLINING {:?} because inline(always) [cost={}]", callsite, cost);
-            Ok(())
-        } else {
-            if cost <= threshold {
-                debug!("INLINING {:?} [cost={} <= threshold={}]", callsite, cost, threshold);
-                Ok(())
-            } else {
-                debug!("NOT inlining {:?} [cost={} > threshold={}]", callsite, cost, threshold);
-                Err("cost above threshold")
-            }
-        }
-    }
-
-    fn inline_call(
-        &self,
-        caller_body: &mut Body<'tcx>,
-        callsite: &CallSite<'tcx>,
-        mut callee_body: Body<'tcx>,
-    ) {
-        let terminator = caller_body[callsite.block].terminator.take().unwrap();
-        match terminator.kind {
-            TerminatorKind::Call { args, destination, cleanup, .. } => {
-                // If the call is something like `a[*i] = f(i)`, where
-                // `i : &mut usize`, then just duplicating the `a[*i]`
-                // Place could result in two different locations if `f`
-                // writes to `i`. To prevent this we need to create a temporary
-                // borrow of the place and pass the destination as `*temp` instead.
-                fn dest_needs_borrow(place: Place<'_>) -> bool {
-                    for elem in place.projection.iter() {
-                        match elem {
-                            ProjectionElem::Deref | ProjectionElem::Index(_) => return true,
-                            _ => {}
-                        }
-                    }
-
-                    false
-                }
-
-                let dest = if let Some((destination_place, _)) = destination {
-                    if dest_needs_borrow(destination_place) {
-                        trace!("creating temp for return destination");
-                        let dest = Rvalue::Ref(
-                            self.tcx.lifetimes.re_erased,
-                            BorrowKind::Mut { allow_two_phase_borrow: false },
-                            destination_place,
-                        );
-                        let dest_ty = dest.ty(caller_body, self.tcx);
-                        let temp = Place::from(self.new_call_temp(caller_body, &callsite, dest_ty));
-                        caller_body[callsite.block].statements.push(Statement {
-                            source_info: callsite.source_info,
-                            kind: StatementKind::Assign(Box::new((temp, dest))),
-                        });
-                        self.tcx.mk_place_deref(temp)
-                    } else {
-                        destination_place
-                    }
-                } else {
-                    trace!("creating temp for return place");
-                    Place::from(self.new_call_temp(caller_body, &callsite, callee_body.return_ty()))
-                };
-
-                // Copy the arguments if needed.
-                let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
-
-                let mut integrator = Integrator {
-                    args: &args,
-                    new_locals: Local::new(caller_body.local_decls.len())..,
-                    new_scopes: SourceScope::new(caller_body.source_scopes.len())..,
-                    new_blocks: BasicBlock::new(caller_body.basic_blocks().len())..,
-                    destination: dest,
-                    return_block: callsite.target,
-                    cleanup_block: cleanup,
-                    in_cleanup_block: false,
-                    tcx: self.tcx,
-                    callsite_span: callsite.source_info.span,
-                    body_span: callee_body.span,
-                    always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
-                };
-
-                // Map all `Local`s, `SourceScope`s and `BasicBlock`s to new ones
-                // (or existing ones, in a few special cases) in the caller.
-                integrator.visit_body(&mut callee_body);
-
-                for scope in &mut callee_body.source_scopes {
-                    // FIXME(eddyb) move this into a `fn visit_scope_data` in `Integrator`.
-                    if scope.parent_scope.is_none() {
-                        let callsite_scope = &caller_body.source_scopes[callsite.source_info.scope];
-
-                        // Attach the outermost callee scope as a child of the callsite
-                        // scope, via the `parent_scope` and `inlined_parent_scope` chains.
-                        scope.parent_scope = Some(callsite.source_info.scope);
-                        assert_eq!(scope.inlined_parent_scope, None);
-                        scope.inlined_parent_scope = if callsite_scope.inlined.is_some() {
-                            Some(callsite.source_info.scope)
-                        } else {
-                            callsite_scope.inlined_parent_scope
-                        };
-
-                        // Mark the outermost callee scope as an inlined one.
-                        assert_eq!(scope.inlined, None);
-                        scope.inlined = Some((callsite.callee, callsite.source_info.span));
-                    } else if scope.inlined_parent_scope.is_none() {
-                        // Make it easy to find the scope with `inlined` set above.
-                        scope.inlined_parent_scope =
-                            Some(integrator.map_scope(OUTERMOST_SOURCE_SCOPE));
-                    }
-                }
-
-                // If there are any locals without storage markers, give them storage only for the
-                // duration of the call.
-                for local in callee_body.vars_and_temps_iter() {
-                    if integrator.always_live_locals.contains(local) {
-                        let new_local = integrator.map_local(local);
-                        caller_body[callsite.block].statements.push(Statement {
-                            source_info: callsite.source_info,
-                            kind: StatementKind::StorageLive(new_local),
-                        });
-                    }
-                }
-                if let Some(block) = callsite.target {
-                    // To avoid repeated O(n) insert, push any new statements to the end and rotate
-                    // the slice once.
-                    let mut n = 0;
-                    for local in callee_body.vars_and_temps_iter().rev() {
-                        if integrator.always_live_locals.contains(local) {
-                            let new_local = integrator.map_local(local);
-                            caller_body[block].statements.push(Statement {
-                                source_info: callsite.source_info,
-                                kind: StatementKind::StorageDead(new_local),
-                            });
-                            n += 1;
-                        }
-                    }
-                    caller_body[block].statements.rotate_right(n);
-                }
-
-                // Insert all of the (mapped) parts of the callee body into the caller.
-                caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
-                caller_body.source_scopes.extend(&mut callee_body.source_scopes.drain(..));
-                caller_body.var_debug_info.append(&mut callee_body.var_debug_info);
-                caller_body.basic_blocks_mut().extend(callee_body.basic_blocks_mut().drain(..));
-
-                caller_body[callsite.block].terminator = Some(Terminator {
-                    source_info: callsite.source_info,
-                    kind: TerminatorKind::Goto { target: integrator.map_block(START_BLOCK) },
-                });
-
-                // Copy only unevaluated constants from the callee_body into the caller_body.
-                // Although we are only pushing `ConstKind::Unevaluated` consts to
-                // `required_consts`, here we may not only have `ConstKind::Unevaluated`
-                // because we are calling `subst_and_normalize_erasing_regions`.
-                caller_body.required_consts.extend(
-                    callee_body.required_consts.iter().copied().filter(|&ct| {
-                        match ct.literal.const_for_ty() {
-                            Some(ct) => matches!(ct.val, ConstKind::Unevaluated(_)),
-                            None => true,
-                        }
-                    }),
-                );
-            }
-            kind => bug!("unexpected terminator kind {:?}", kind),
-        }
-    }
-
-    fn make_call_args(
-        &self,
-        args: Vec<Operand<'tcx>>,
-        callsite: &CallSite<'tcx>,
-        caller_body: &mut Body<'tcx>,
-        callee_body: &Body<'tcx>,
-    ) -> Vec<Local> {
-        let tcx = self.tcx;
-
-        // There is a bit of a mismatch between the *caller* of a closure and the *callee*.
-        // The caller provides the arguments wrapped up in a tuple:
-        //
-        //     tuple_tmp = (a, b, c)
-        //     Fn::call(closure_ref, tuple_tmp)
-        //
-        // meanwhile the closure body expects the arguments (here, `a`, `b`, and `c`)
-        // as distinct arguments. (This is the "rust-call" ABI hack.) Normally, codegen has
-        // the job of unpacking this tuple. But here, we are codegen. =) So we want to create
-        // a vector like
-        //
-        //     [closure_ref, tuple_tmp.0, tuple_tmp.1, tuple_tmp.2]
-        //
-        // Except for one tiny wrinkle: we don't actually want `tuple_tmp.0`. It's more convenient
-        // if we "spill" that into *another* temporary, so that we can map the argument
-        // variable in the callee MIR directly to an argument variable on our side.
-        // So we introduce temporaries like:
-        //
-        //     tmp0 = tuple_tmp.0
-        //     tmp1 = tuple_tmp.1
-        //     tmp2 = tuple_tmp.2
-        //
-        // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
-        if callsite.fn_sig.abi() == Abi::RustCall && callee_body.spread_arg.is_none() {
-            let mut args = args.into_iter();
-            let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
-            let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body);
-            assert!(args.next().is_none());
-
-            let tuple = Place::from(tuple);
-            let tuple_tys = if let ty::Tuple(s) = tuple.ty(caller_body, tcx).ty.kind() {
-                s
-            } else {
-                bug!("Closure arguments are not passed as a tuple");
-            };
-
-            // The `closure_ref` in our example above.
-            let closure_ref_arg = iter::once(self_);
-
-            // The `tmp0`, `tmp1`, and `tmp2` in our example abonve.
-            let tuple_tmp_args = tuple_tys.iter().enumerate().map(|(i, ty)| {
-                // This is e.g., `tuple_tmp.0` in our example above.
-                let tuple_field =
-                    Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
-
-                // Spill to a local to make e.g., `tmp0`.
-                self.create_temp_if_necessary(tuple_field, callsite, caller_body)
-            });
-
-            closure_ref_arg.chain(tuple_tmp_args).collect()
-        } else {
-            args.into_iter()
-                .map(|a| self.create_temp_if_necessary(a, callsite, caller_body))
-                .collect()
-        }
-    }
-
-    /// If `arg` is already a temporary, returns it. Otherwise, introduces a fresh
-    /// temporary `T` and an instruction `T = arg`, and returns `T`.
-    fn create_temp_if_necessary(
-        &self,
-        arg: Operand<'tcx>,
-        callsite: &CallSite<'tcx>,
-        caller_body: &mut Body<'tcx>,
-    ) -> Local {
-        // Reuse the operand if it is a moved temporary.
-        if let Operand::Move(place) = &arg {
-            if let Some(local) = place.as_local() {
-                if caller_body.local_kind(local) == LocalKind::Temp {
-                    return local;
-                }
-            }
-        }
-
-        // Otherwise, create a temporary for the argument.
-        trace!("creating temp for argument {:?}", arg);
-        let arg_ty = arg.ty(caller_body, self.tcx);
-        let local = self.new_call_temp(caller_body, callsite, arg_ty);
-        caller_body[callsite.block].statements.push(Statement {
-            source_info: callsite.source_info,
-            kind: StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg)))),
-        });
-        local
-    }
-
-    /// Introduces a new temporary into the caller body that is live for the duration of the call.
-    fn new_call_temp(
-        &self,
-        caller_body: &mut Body<'tcx>,
-        callsite: &CallSite<'tcx>,
-        ty: Ty<'tcx>,
-    ) -> Local {
-        let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
-
-        caller_body[callsite.block].statements.push(Statement {
-            source_info: callsite.source_info,
-            kind: StatementKind::StorageLive(local),
-        });
-
-        if let Some(block) = callsite.target {
-            caller_body[block].statements.insert(
-                0,
-                Statement {
-                    source_info: callsite.source_info,
-                    kind: StatementKind::StorageDead(local),
-                },
-            );
-        }
-
-        local
-    }
-}
-
-fn type_size_of<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    ty: Ty<'tcx>,
-) -> Option<u64> {
-    tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
-}
-
-/**
- * Integrator.
- *
- * Integrates blocks from the callee function into the calling function.
- * Updates block indices, references to locals and other control flow
- * stuff.
-*/
-struct Integrator<'a, 'tcx> {
-    args: &'a [Local],
-    new_locals: RangeFrom<Local>,
-    new_scopes: RangeFrom<SourceScope>,
-    new_blocks: RangeFrom<BasicBlock>,
-    destination: Place<'tcx>,
-    return_block: Option<BasicBlock>,
-    cleanup_block: Option<BasicBlock>,
-    in_cleanup_block: bool,
-    tcx: TyCtxt<'tcx>,
-    callsite_span: Span,
-    body_span: Span,
-    always_live_locals: BitSet<Local>,
-}
-
-impl<'a, 'tcx> Integrator<'a, 'tcx> {
-    fn map_local(&self, local: Local) -> Local {
-        let new = if local == RETURN_PLACE {
-            self.destination.local
-        } else {
-            let idx = local.index() - 1;
-            if idx < self.args.len() {
-                self.args[idx]
-            } else {
-                Local::new(self.new_locals.start.index() + (idx - self.args.len()))
-            }
-        };
-        trace!("mapping local `{:?}` to `{:?}`", local, new);
-        new
-    }
-
-    fn map_scope(&self, scope: SourceScope) -> SourceScope {
-        let new = SourceScope::new(self.new_scopes.start.index() + scope.index());
-        trace!("mapping scope `{:?}` to `{:?}`", scope, new);
-        new
-    }
-
-    fn map_block(&self, block: BasicBlock) -> BasicBlock {
-        let new = BasicBlock::new(self.new_blocks.start.index() + block.index());
-        trace!("mapping block `{:?}` to `{:?}`", block, new);
-        new
-    }
-}
-
-impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, local: &mut Local, _ctxt: PlaceContext, _location: Location) {
-        *local = self.map_local(*local);
-    }
-
-    fn visit_source_scope(&mut self, scope: &mut SourceScope) {
-        *scope = self.map_scope(*scope);
-    }
-
-    fn visit_span(&mut self, span: &mut Span) {
-        let mut expn_data =
-            ExpnData::default(ExpnKind::Inlined, *span, self.tcx.sess.edition(), None, None);
-        expn_data.def_site = self.body_span;
-        // Make sure that all spans track the fact that they were inlined.
-        *span =
-            self.callsite_span.fresh_expansion(expn_data, self.tcx.create_stable_hashing_context());
-    }
-
-    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
-        for elem in place.projection {
-            // FIXME: Make sure that return place is not used in an indexing projection, since it
-            // won't be rebased as it is supposed to be.
-            assert_ne!(ProjectionElem::Index(RETURN_PLACE), elem);
-        }
-
-        // If this is the `RETURN_PLACE`, we need to rebase any projections onto it.
-        let dest_proj_len = self.destination.projection.len();
-        if place.local == RETURN_PLACE && dest_proj_len > 0 {
-            let mut projs = Vec::with_capacity(dest_proj_len + place.projection.len());
-            projs.extend(self.destination.projection);
-            projs.extend(place.projection);
-
-            place.projection = self.tcx.intern_place_elems(&*projs);
-        }
-        // Handles integrating any locals that occur in the base
-        // or projections
-        self.super_place(place, context, location)
-    }
-
-    fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
-        self.in_cleanup_block = data.is_cleanup;
-        self.super_basic_block_data(block, data);
-        self.in_cleanup_block = false;
-    }
-
-    fn visit_retag(&mut self, kind: &mut RetagKind, place: &mut Place<'tcx>, loc: Location) {
-        self.super_retag(kind, place, loc);
-
-        // We have to patch all inlined retags to be aware that they are no longer
-        // happening on function entry.
-        if *kind == RetagKind::FnEntry {
-            *kind = RetagKind::Default;
-        }
-    }
-
-    fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
-        if let StatementKind::StorageLive(local) | StatementKind::StorageDead(local) =
-            statement.kind
-        {
-            self.always_live_locals.remove(local);
-        }
-        self.super_statement(statement, location);
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, loc: Location) {
-        // Don't try to modify the implicit `_0` access on return (`return` terminators are
-        // replaced down below anyways).
-        if !matches!(terminator.kind, TerminatorKind::Return) {
-            self.super_terminator(terminator, loc);
-        }
-
-        match terminator.kind {
-            TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => bug!(),
-            TerminatorKind::Goto { ref mut target } => {
-                *target = self.map_block(*target);
-            }
-            TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                for tgt in targets.all_targets_mut() {
-                    *tgt = self.map_block(*tgt);
-                }
-            }
-            TerminatorKind::Drop { ref mut target, ref mut unwind, .. }
-            | TerminatorKind::DropAndReplace { ref mut target, ref mut unwind, .. } => {
-                *target = self.map_block(*target);
-                if let Some(tgt) = *unwind {
-                    *unwind = Some(self.map_block(tgt));
-                } else if !self.in_cleanup_block {
-                    // Unless this drop is in a cleanup block, add an unwind edge to
-                    // the original call's cleanup block
-                    *unwind = self.cleanup_block;
-                }
-            }
-            TerminatorKind::Call { ref mut destination, ref mut cleanup, .. } => {
-                if let Some((_, ref mut tgt)) = *destination {
-                    *tgt = self.map_block(*tgt);
-                }
-                if let Some(tgt) = *cleanup {
-                    *cleanup = Some(self.map_block(tgt));
-                } else if !self.in_cleanup_block {
-                    // Unless this call is in a cleanup block, add an unwind edge to
-                    // the original call's cleanup block
-                    *cleanup = self.cleanup_block;
-                }
-            }
-            TerminatorKind::Assert { ref mut target, ref mut cleanup, .. } => {
-                *target = self.map_block(*target);
-                if let Some(tgt) = *cleanup {
-                    *cleanup = Some(self.map_block(tgt));
-                } else if !self.in_cleanup_block {
-                    // Unless this assert is in a cleanup block, add an unwind edge to
-                    // the original call's cleanup block
-                    *cleanup = self.cleanup_block;
-                }
-            }
-            TerminatorKind::Return => {
-                terminator.kind = if let Some(tgt) = self.return_block {
-                    TerminatorKind::Goto { target: tgt }
-                } else {
-                    TerminatorKind::Unreachable
-                }
-            }
-            TerminatorKind::Resume => {
-                if let Some(tgt) = self.cleanup_block {
-                    terminator.kind = TerminatorKind::Goto { target: tgt }
-                }
-            }
-            TerminatorKind::Abort => {}
-            TerminatorKind::Unreachable => {}
-            TerminatorKind::FalseEdge { ref mut real_target, ref mut imaginary_target } => {
-                *real_target = self.map_block(*real_target);
-                *imaginary_target = self.map_block(*imaginary_target);
-            }
-            TerminatorKind::FalseUnwind { real_target: _, unwind: _ } =>
-            // see the ordering of passes in the optimized_mir query.
-            {
-                bug!("False unwinds should have been removed before inlining")
-            }
-            TerminatorKind::InlineAsm { ref mut destination, .. } => {
-                if let Some(ref mut tgt) = *destination {
-                    *tgt = self.map_block(*tgt);
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/inline/cycle.rs b/compiler/rustc_mir/src/transform/inline/cycle.rs
deleted file mode 100644
index 385394ba67d..00000000000
--- a/compiler/rustc_mir/src/transform/inline/cycle.rs
+++ /dev/null
@@ -1,169 +0,0 @@
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::sso::SsoHashSet;
-use rustc_data_structures::stack::ensure_sufficient_stack;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::mir::TerminatorKind;
-use rustc_middle::ty::TypeFoldable;
-use rustc_middle::ty::{self, subst::SubstsRef, InstanceDef, TyCtxt};
-use rustc_session::Limit;
-
-// FIXME: check whether it is cheaper to precompute the entire call graph instead of invoking
-// this query riddiculously often.
-#[instrument(level = "debug", skip(tcx, root, target))]
-crate fn mir_callgraph_reachable(
-    tcx: TyCtxt<'tcx>,
-    (root, target): (ty::Instance<'tcx>, LocalDefId),
-) -> bool {
-    trace!(%root, target = %tcx.def_path_str(target.to_def_id()));
-    let param_env = tcx.param_env_reveal_all_normalized(target);
-    assert_ne!(
-        root.def_id().expect_local(),
-        target,
-        "you should not call `mir_callgraph_reachable` on immediate self recursion"
-    );
-    assert!(
-        matches!(root.def, InstanceDef::Item(_)),
-        "you should not call `mir_callgraph_reachable` on shims"
-    );
-    assert!(
-        !tcx.is_constructor(root.def_id()),
-        "you should not call `mir_callgraph_reachable` on enum/struct constructor functions"
-    );
-    #[instrument(
-        level = "debug",
-        skip(tcx, param_env, target, stack, seen, recursion_limiter, caller, recursion_limit)
-    )]
-    fn process(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        caller: ty::Instance<'tcx>,
-        target: LocalDefId,
-        stack: &mut Vec<ty::Instance<'tcx>>,
-        seen: &mut FxHashSet<ty::Instance<'tcx>>,
-        recursion_limiter: &mut FxHashMap<DefId, usize>,
-        recursion_limit: Limit,
-    ) -> bool {
-        trace!(%caller);
-        for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
-            let substs = caller.subst_mir_and_normalize_erasing_regions(tcx, param_env, substs);
-            let callee = match ty::Instance::resolve(tcx, param_env, callee, substs).unwrap() {
-                Some(callee) => callee,
-                None => {
-                    trace!(?callee, "cannot resolve, skipping");
-                    continue;
-                }
-            };
-
-            // Found a path.
-            if callee.def_id() == target.to_def_id() {
-                return true;
-            }
-
-            if tcx.is_constructor(callee.def_id()) {
-                trace!("constructors always have MIR");
-                // Constructor functions cannot cause a query cycle.
-                continue;
-            }
-
-            match callee.def {
-                InstanceDef::Item(_) => {
-                    // If there is no MIR available (either because it was not in metadata or
-                    // because it has no MIR because it's an extern function), then the inliner
-                    // won't cause cycles on this.
-                    if !tcx.is_mir_available(callee.def_id()) {
-                        trace!(?callee, "no mir available, skipping");
-                        continue;
-                    }
-                }
-                // These have no own callable MIR.
-                InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue,
-                // These have MIR and if that MIR is inlined, substituted and then inlining is run
-                // again, a function item can end up getting inlined. Thus we'll be able to cause
-                // a cycle that way
-                InstanceDef::VtableShim(_)
-                | InstanceDef::ReifyShim(_)
-                | InstanceDef::FnPtrShim(..)
-                | InstanceDef::ClosureOnceShim { .. }
-                | InstanceDef::CloneShim(..) => {}
-                InstanceDef::DropGlue(..) => {
-                    // FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
-                    // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
-                    // needs some more analysis.
-                    if callee.definitely_needs_subst(tcx) {
-                        continue;
-                    }
-                }
-            }
-
-            if seen.insert(callee) {
-                let recursion = recursion_limiter.entry(callee.def_id()).or_default();
-                trace!(?callee, recursion = *recursion);
-                if recursion_limit.value_within_limit(*recursion) {
-                    *recursion += 1;
-                    stack.push(callee);
-                    let found_recursion = ensure_sufficient_stack(|| {
-                        process(
-                            tcx,
-                            param_env,
-                            callee,
-                            target,
-                            stack,
-                            seen,
-                            recursion_limiter,
-                            recursion_limit,
-                        )
-                    });
-                    if found_recursion {
-                        return true;
-                    }
-                    stack.pop();
-                } else {
-                    // Pessimistically assume that there could be recursion.
-                    return true;
-                }
-            }
-        }
-        false
-    }
-    process(
-        tcx,
-        param_env,
-        root,
-        target,
-        &mut Vec::new(),
-        &mut FxHashSet::default(),
-        &mut FxHashMap::default(),
-        tcx.recursion_limit(),
-    )
-}
-
-crate fn mir_inliner_callees<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    instance: ty::InstanceDef<'tcx>,
-) -> &'tcx [(DefId, SubstsRef<'tcx>)] {
-    let steal;
-    let guard;
-    let body = match (instance, instance.def_id().as_local()) {
-        (InstanceDef::Item(_), Some(def_id)) => {
-            let def = ty::WithOptConstParam::unknown(def_id);
-            steal = tcx.mir_promoted(def).0;
-            guard = steal.borrow();
-            &*guard
-        }
-        // Functions from other crates and MIR shims
-        _ => tcx.instance_mir(instance),
-    };
-    let mut calls = SsoHashSet::new();
-    for bb_data in body.basic_blocks() {
-        let terminator = bb_data.terminator();
-        if let TerminatorKind::Call { func, .. } = &terminator.kind {
-            let ty = func.ty(&body.local_decls, tcx);
-            let call = match ty.kind() {
-                ty::FnDef(def_id, substs) => (*def_id, *substs),
-                _ => continue,
-            };
-            calls.insert(call);
-        }
-    }
-    tcx.arena.alloc_from_iter(calls.iter().copied())
-}
diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs
deleted file mode 100644
index 805f546104c..00000000000
--- a/compiler/rustc_mir/src/transform/instcombine.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-//! Performs various peephole optimizations.
-
-use crate::transform::MirPass;
-use rustc_hir::Mutability;
-use rustc_middle::mir::{
-    BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
-    StatementKind, UnOp,
-};
-use rustc_middle::ty::{self, TyCtxt};
-
-pub struct InstCombine;
-
-impl<'tcx> MirPass<'tcx> for InstCombine {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let ctx = InstCombineContext { tcx, local_decls };
-        for block in basic_blocks.iter_mut() {
-            for statement in block.statements.iter_mut() {
-                match statement.kind {
-                    StatementKind::Assign(box (_place, ref mut rvalue)) => {
-                        ctx.combine_bool_cmp(&statement.source_info, rvalue);
-                        ctx.combine_ref_deref(&statement.source_info, rvalue);
-                        ctx.combine_len(&statement.source_info, rvalue);
-                    }
-                    _ => {}
-                }
-            }
-        }
-    }
-}
-
-struct InstCombineContext<'tcx, 'a> {
-    tcx: TyCtxt<'tcx>,
-    local_decls: &'a LocalDecls<'tcx>,
-}
-
-impl<'tcx, 'a> InstCombineContext<'tcx, 'a> {
-    fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
-        self.tcx.consider_optimizing(|| {
-            format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
-        })
-    }
-
-    /// Transform boolean comparisons into logical operations.
-    fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
-        match rvalue {
-            Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
-                let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
-                    // Transform "Eq(a, true)" ==> "a"
-                    (BinOp::Eq, _, Some(true)) => Some(Rvalue::Use(a.clone())),
-
-                    // Transform "Ne(a, false)" ==> "a"
-                    (BinOp::Ne, _, Some(false)) => Some(Rvalue::Use(a.clone())),
-
-                    // Transform "Eq(true, b)" ==> "b"
-                    (BinOp::Eq, Some(true), _) => Some(Rvalue::Use(b.clone())),
-
-                    // Transform "Ne(false, b)" ==> "b"
-                    (BinOp::Ne, Some(false), _) => Some(Rvalue::Use(b.clone())),
-
-                    // Transform "Eq(false, b)" ==> "Not(b)"
-                    (BinOp::Eq, Some(false), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
-
-                    // Transform "Ne(true, b)" ==> "Not(b)"
-                    (BinOp::Ne, Some(true), _) => Some(Rvalue::UnaryOp(UnOp::Not, b.clone())),
-
-                    // Transform "Eq(a, false)" ==> "Not(a)"
-                    (BinOp::Eq, _, Some(false)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
-
-                    // Transform "Ne(a, true)" ==> "Not(a)"
-                    (BinOp::Ne, _, Some(true)) => Some(Rvalue::UnaryOp(UnOp::Not, a.clone())),
-
-                    _ => None,
-                };
-
-                if let Some(new) = new {
-                    if self.should_combine(source_info, rvalue) {
-                        *rvalue = new;
-                    }
-                }
-            }
-
-            _ => {}
-        }
-    }
-
-    fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
-        let a = a.constant()?;
-        if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None }
-    }
-
-    /// Transform "&(*a)" ==> "a".
-    fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
-        if let Rvalue::Ref(_, _, place) = rvalue {
-            if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
-                if let ty::Ref(_, _, Mutability::Not) =
-                    base.ty(self.local_decls, self.tcx).ty.kind()
-                {
-                    // The dereferenced place must have type `&_`, so that we don't copy `&mut _`.
-                } else {
-                    return;
-                }
-
-                if !self.should_combine(source_info, rvalue) {
-                    return;
-                }
-
-                *rvalue = Rvalue::Use(Operand::Copy(Place {
-                    local: base.local,
-                    projection: self.tcx.intern_place_elems(base.projection),
-                }));
-            }
-        }
-    }
-
-    /// Transform "Len([_; N])" ==> "N".
-    fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
-        if let Rvalue::Len(ref place) = *rvalue {
-            let place_ty = place.ty(self.local_decls, self.tcx).ty;
-            if let ty::Array(_, len) = *place_ty.kind() {
-                if !self.should_combine(source_info, rvalue) {
-                    return;
-                }
-
-                let constant =
-                    Constant { span: source_info.span, literal: len.into(), user_ty: None };
-                *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/lower_intrinsics.rs b/compiler/rustc_mir/src/transform/lower_intrinsics.rs
deleted file mode 100644
index e9f1d4f2ce8..00000000000
--- a/compiler/rustc_mir/src/transform/lower_intrinsics.rs
+++ /dev/null
@@ -1,154 +0,0 @@
-//! Lowers intrinsic calls
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::{sym, Symbol};
-use rustc_span::Span;
-use rustc_target::spec::abi::Abi;
-
-pub struct LowerIntrinsics;
-
-impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks {
-            let terminator = block.terminator.as_mut().unwrap();
-            if let TerminatorKind::Call { func, args, destination, .. } = &mut terminator.kind {
-                let func_ty = func.ty(local_decls, tcx);
-                let (intrinsic_name, substs) = match resolve_rust_intrinsic(tcx, func_ty) {
-                    None => continue,
-                    Some(it) => it,
-                };
-                match intrinsic_name {
-                    sym::unreachable => {
-                        terminator.kind = TerminatorKind::Unreachable;
-                    }
-                    sym::forget => {
-                        if let Some((destination, target)) = *destination {
-                            block.statements.push(Statement {
-                                source_info: terminator.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    destination,
-                                    Rvalue::Use(Operand::Constant(Box::new(Constant {
-                                        span: terminator.source_info.span,
-                                        user_ty: None,
-                                        literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
-                                    }))),
-                                ))),
-                            });
-                            terminator.kind = TerminatorKind::Goto { target };
-                        }
-                    }
-                    sym::copy_nonoverlapping => {
-                        let target = destination.unwrap().1;
-                        let mut args = args.drain(..);
-                        block.statements.push(Statement {
-                            source_info: terminator.source_info,
-                            kind: StatementKind::CopyNonOverlapping(Box::new(
-                                rustc_middle::mir::CopyNonOverlapping {
-                                    src: args.next().unwrap(),
-                                    dst: args.next().unwrap(),
-                                    count: args.next().unwrap(),
-                                },
-                            )),
-                        });
-                        assert_eq!(
-                            args.next(),
-                            None,
-                            "Extra argument for copy_non_overlapping intrinsic"
-                        );
-                        drop(args);
-                        terminator.kind = TerminatorKind::Goto { target };
-                    }
-                    sym::wrapping_add | sym::wrapping_sub | sym::wrapping_mul => {
-                        if let Some((destination, target)) = *destination {
-                            let lhs;
-                            let rhs;
-                            {
-                                let mut args = args.drain(..);
-                                lhs = args.next().unwrap();
-                                rhs = args.next().unwrap();
-                            }
-                            let bin_op = match intrinsic_name {
-                                sym::wrapping_add => BinOp::Add,
-                                sym::wrapping_sub => BinOp::Sub,
-                                sym::wrapping_mul => BinOp::Mul,
-                                _ => bug!("unexpected intrinsic"),
-                            };
-                            block.statements.push(Statement {
-                                source_info: terminator.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    destination,
-                                    Rvalue::BinaryOp(bin_op, Box::new((lhs, rhs))),
-                                ))),
-                            });
-                            terminator.kind = TerminatorKind::Goto { target };
-                        }
-                    }
-                    sym::add_with_overflow | sym::sub_with_overflow | sym::mul_with_overflow => {
-                        // The checked binary operations are not suitable target for lowering here,
-                        // since their semantics depend on the value of overflow-checks flag used
-                        // during codegen. Issue #35310.
-                    }
-                    sym::size_of => {
-                        if let Some((destination, target)) = *destination {
-                            let tp_ty = substs.type_at(0);
-                            block.statements.push(Statement {
-                                source_info: terminator.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    destination,
-                                    Rvalue::NullaryOp(NullOp::SizeOf, tp_ty),
-                                ))),
-                            });
-                            terminator.kind = TerminatorKind::Goto { target };
-                        }
-                    }
-                    sym::discriminant_value => {
-                        if let (Some((destination, target)), Some(arg)) =
-                            (*destination, args[0].place())
-                        {
-                            let arg = tcx.mk_place_deref(arg);
-                            block.statements.push(Statement {
-                                source_info: terminator.source_info,
-                                kind: StatementKind::Assign(Box::new((
-                                    destination,
-                                    Rvalue::Discriminant(arg),
-                                ))),
-                            });
-                            terminator.kind = TerminatorKind::Goto { target };
-                        }
-                    }
-                    _ if intrinsic_name.as_str().starts_with("simd_shuffle") => {
-                        validate_simd_shuffle(tcx, args, terminator.source_info.span);
-                    }
-                    _ => {}
-                }
-            }
-        }
-    }
-}
-
-fn resolve_rust_intrinsic(
-    tcx: TyCtxt<'tcx>,
-    func_ty: Ty<'tcx>,
-) -> Option<(Symbol, SubstsRef<'tcx>)> {
-    if let ty::FnDef(def_id, substs) = *func_ty.kind() {
-        let fn_sig = func_ty.fn_sig(tcx);
-        if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() {
-            return Some((tcx.item_name(def_id), substs));
-        }
-    }
-    None
-}
-
-fn validate_simd_shuffle(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
-    match &args[2] {
-        Operand::Constant(_) => {} // all good
-        _ => {
-            let msg = "last argument of `simd_shuffle` is required to be a `const` item";
-            tcx.sess.span_err(span, msg);
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/lower_slice_len.rs b/compiler/rustc_mir/src/transform/lower_slice_len.rs
deleted file mode 100644
index c3eb2d9f921..00000000000
--- a/compiler/rustc_mir/src/transform/lower_slice_len.rs
+++ /dev/null
@@ -1,100 +0,0 @@
-//! This pass lowers calls to core::slice::len to just Len op.
-//! It should run before inlining!
-
-use crate::transform::MirPass;
-use rustc_hir::def_id::DefId;
-use rustc_index::vec::IndexVec;
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, TyCtxt};
-
-pub struct LowerSliceLenCalls;
-
-impl<'tcx> MirPass<'tcx> for LowerSliceLenCalls {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        lower_slice_len_calls(tcx, body)
-    }
-}
-
-pub fn lower_slice_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let language_items = tcx.lang_items();
-    let slice_len_fn_item_def_id = if let Some(slice_len_fn_item) = language_items.slice_len_fn() {
-        slice_len_fn_item
-    } else {
-        // there is no language item to compare to :)
-        return;
-    };
-
-    let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-
-    for block in basic_blocks {
-        // lower `<[_]>::len` calls
-        lower_slice_len_call(tcx, block, &*local_decls, slice_len_fn_item_def_id);
-    }
-}
-
-struct SliceLenPatchInformation<'tcx> {
-    add_statement: Statement<'tcx>,
-    new_terminator_kind: TerminatorKind<'tcx>,
-}
-
-fn lower_slice_len_call<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    block: &mut BasicBlockData<'tcx>,
-    local_decls: &IndexVec<Local, LocalDecl<'tcx>>,
-    slice_len_fn_item_def_id: DefId,
-) {
-    let mut patch_found: Option<SliceLenPatchInformation<'_>> = None;
-
-    let terminator = block.terminator();
-    match &terminator.kind {
-        TerminatorKind::Call {
-            func,
-            args,
-            destination: Some((dest, bb)),
-            cleanup: None,
-            from_hir_call: true,
-            ..
-        } => {
-            // some heuristics for fast rejection
-            if args.len() != 1 {
-                return;
-            }
-            let arg = match args[0].place() {
-                Some(arg) => arg,
-                None => return,
-            };
-            let func_ty = func.ty(local_decls, tcx);
-            match func_ty.kind() {
-                ty::FnDef(fn_def_id, _) if fn_def_id == &slice_len_fn_item_def_id => {
-                    // perform modifications
-                    // from something like `_5 = core::slice::<impl [u8]>::len(move _6) -> bb1`
-                    // into `_5 = Len(*_6)
-                    // goto bb1
-
-                    // make new RValue for Len
-                    let deref_arg = tcx.mk_place_deref(arg);
-                    let r_value = Rvalue::Len(deref_arg);
-                    let len_statement_kind = StatementKind::Assign(Box::new((*dest, r_value)));
-                    let add_statement = Statement {
-                        kind: len_statement_kind,
-                        source_info: terminator.source_info.clone(),
-                    };
-
-                    // modify terminator into simple Goto
-                    let new_terminator_kind = TerminatorKind::Goto { target: bb.clone() };
-
-                    let patch = SliceLenPatchInformation { add_statement, new_terminator_kind };
-
-                    patch_found = Some(patch);
-                }
-                _ => {}
-            }
-        }
-        _ => {}
-    }
-
-    if let Some(SliceLenPatchInformation { add_statement, new_terminator_kind }) = patch_found {
-        block.statements.push(add_statement);
-        block.terminator_mut().kind = new_terminator_kind;
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs
deleted file mode 100644
index 37a3fa50a52..00000000000
--- a/compiler/rustc_mir/src/transform/match_branches.rs
+++ /dev/null
@@ -1,176 +0,0 @@
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use std::iter;
-
-use super::simplify::simplify_cfg;
-
-pub struct MatchBranchSimplification;
-
-/// If a source block is found that switches between two blocks that are exactly
-/// the same modulo const bool assignments (e.g., one assigns true another false
-/// to the same place), merge a target block statements into the source block,
-/// using Eq / Ne comparison with switch value where const bools value differ.
-///
-/// For example:
-///
-/// ```rust
-/// bb0: {
-///     switchInt(move _3) -> [42_isize: bb1, otherwise: bb2];
-/// }
-///
-/// bb1: {
-///     _2 = const true;
-///     goto -> bb3;
-/// }
-///
-/// bb2: {
-///     _2 = const false;
-///     goto -> bb3;
-/// }
-/// ```
-///
-/// into:
-///
-/// ```rust
-/// bb0: {
-///    _2 = Eq(move _3, const 42_isize);
-///    goto -> bb3;
-/// }
-/// ```
-
-impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 3 {
-            return;
-        }
-
-        let def_id = body.source.def_id();
-        let param_env = tcx.param_env(def_id);
-
-        let (bbs, local_decls) = body.basic_blocks_and_local_decls_mut();
-        let mut should_cleanup = false;
-        'outer: for bb_idx in bbs.indices() {
-            if !tcx.consider_optimizing(|| format!("MatchBranchSimplification {:?} ", def_id)) {
-                continue;
-            }
-
-            let (discr, val, switch_ty, first, second) = match bbs[bb_idx].terminator().kind {
-                TerminatorKind::SwitchInt {
-                    discr: ref discr @ (Operand::Copy(_) | Operand::Move(_)),
-                    switch_ty,
-                    ref targets,
-                    ..
-                } if targets.iter().len() == 1 => {
-                    let (value, target) = targets.iter().next().unwrap();
-                    if target == targets.otherwise() {
-                        continue;
-                    }
-                    (discr, value, switch_ty, target, targets.otherwise())
-                }
-                // Only optimize switch int statements
-                _ => continue,
-            };
-
-            // Check that destinations are identical, and if not, then don't optimize this block
-            if bbs[first].terminator().kind != bbs[second].terminator().kind {
-                continue;
-            }
-
-            // Check that blocks are assignments of consts to the same place or same statement,
-            // and match up 1-1, if not don't optimize this block.
-            let first_stmts = &bbs[first].statements;
-            let scnd_stmts = &bbs[second].statements;
-            if first_stmts.len() != scnd_stmts.len() {
-                continue;
-            }
-            for (f, s) in iter::zip(first_stmts, scnd_stmts) {
-                match (&f.kind, &s.kind) {
-                    // If two statements are exactly the same, we can optimize.
-                    (f_s, s_s) if f_s == s_s => {}
-
-                    // If two statements are const bool assignments to the same place, we can optimize.
-                    (
-                        StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
-                        StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) if lhs_f == lhs_s
-                        && f_c.literal.ty().is_bool()
-                        && s_c.literal.ty().is_bool()
-                        && f_c.literal.try_eval_bool(tcx, param_env).is_some()
-                        && s_c.literal.try_eval_bool(tcx, param_env).is_some() => {}
-
-                    // Otherwise we cannot optimize. Try another block.
-                    _ => continue 'outer,
-                }
-            }
-            // Take ownership of items now that we know we can optimize.
-            let discr = discr.clone();
-
-            // Introduce a temporary for the discriminant value.
-            let source_info = bbs[bb_idx].terminator().source_info;
-            let discr_local = local_decls.push(LocalDecl::new(switch_ty, source_info.span));
-
-            // We already checked that first and second are different blocks,
-            // and bb_idx has a different terminator from both of them.
-            let (from, first, second) = bbs.pick3_mut(bb_idx, first, second);
-
-            let new_stmts = iter::zip(&first.statements, &second.statements).map(|(f, s)| {
-                match (&f.kind, &s.kind) {
-                    (f_s, s_s) if f_s == s_s => (*f).clone(),
-
-                    (
-                        StatementKind::Assign(box (lhs, Rvalue::Use(Operand::Constant(f_c)))),
-                        StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
-                    ) => {
-                        // From earlier loop we know that we are dealing with bool constants only:
-                        let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
-                        let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
-                        if f_b == s_b {
-                            // Same value in both blocks. Use statement as is.
-                            (*f).clone()
-                        } else {
-                            // Different value between blocks. Make value conditional on switch condition.
-                            let size = tcx.layout_of(param_env.and(switch_ty)).unwrap().size;
-                            let const_cmp = Operand::const_from_scalar(
-                                tcx,
-                                switch_ty,
-                                crate::interpret::Scalar::from_uint(val, size),
-                                rustc_span::DUMMY_SP,
-                            );
-                            let op = if f_b { BinOp::Eq } else { BinOp::Ne };
-                            let rhs = Rvalue::BinaryOp(
-                                op,
-                                Box::new((Operand::Copy(Place::from(discr_local)), const_cmp)),
-                            );
-                            Statement {
-                                source_info: f.source_info,
-                                kind: StatementKind::Assign(Box::new((*lhs, rhs))),
-                            }
-                        }
-                    }
-
-                    _ => unreachable!(),
-                }
-            });
-
-            from.statements
-                .push(Statement { source_info, kind: StatementKind::StorageLive(discr_local) });
-            from.statements.push(Statement {
-                source_info,
-                kind: StatementKind::Assign(Box::new((
-                    Place::from(discr_local),
-                    Rvalue::Use(discr),
-                ))),
-            });
-            from.statements.extend(new_stmts);
-            from.statements
-                .push(Statement { source_info, kind: StatementKind::StorageDead(discr_local) });
-            from.terminator_mut().kind = first.terminator().kind.clone();
-            should_cleanup = true;
-        }
-
-        if should_cleanup {
-            simplify_cfg(tcx, body);
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs
index d4c2456e9a4..abf43dd1d23 100644
--- a/compiler/rustc_mir/src/transform/mod.rs
+++ b/compiler/rustc_mir/src/transform/mod.rs
@@ -1,149 +1,12 @@
-use crate::{shim, util};
-use required_consts::RequiredConstsVisitor;
-use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::steal::Steal;
-use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
-use rustc_index::vec::IndexVec;
-use rustc_middle::mir::visit::Visitor as _;
-use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPhase, Promoted};
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, TyCtxt, TypeFoldable};
-use rustc_span::{Span, Symbol};
+use rustc_middle::mir::Body;
+use rustc_middle::ty::TyCtxt;
 use std::borrow::Cow;
 
-pub mod abort_unwinding_calls;
-pub mod add_call_guards;
-pub mod add_moves_for_packed_drops;
-pub mod add_retag;
-pub mod check_const_item_mutation;
 pub mod check_consts;
-pub mod check_packed_ref;
-pub mod check_unsafety;
-pub mod cleanup_post_borrowck;
-pub mod const_debuginfo;
-pub mod const_goto;
-pub mod const_prop;
-pub mod coverage;
-pub mod deaggregator;
-pub mod deduplicate_blocks;
-pub mod dest_prop;
-pub mod dump_mir;
-pub mod early_otherwise_branch;
-pub mod elaborate_drops;
-pub mod function_item_references;
-pub mod generator;
-pub mod inline;
-pub mod instcombine;
-pub mod lower_intrinsics;
-pub mod lower_slice_len;
-pub mod match_branches;
-pub mod multiple_return_terminators;
-pub mod nrvo;
 pub mod promote_consts;
-pub mod remove_noop_landing_pads;
-pub mod remove_storage_markers;
-pub mod remove_unneeded_drops;
-pub mod remove_zsts;
-pub mod required_consts;
 pub mod rustc_peek;
-pub mod separate_const_switch;
-pub mod simplify;
-pub mod simplify_branches;
-pub mod simplify_comparison_integral;
-pub mod simplify_try;
-pub mod uninhabited_enum_branching;
-pub mod unreachable_prop;
 pub mod validate;
 
-pub use rustc_middle::mir::MirSource;
-
-pub(crate) fn provide(providers: &mut Providers) {
-    self::check_unsafety::provide(providers);
-    self::check_packed_ref::provide(providers);
-    *providers = Providers {
-        mir_keys,
-        mir_const,
-        mir_const_qualif: |tcx, def_id| {
-            let def_id = def_id.expect_local();
-            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.mir_const_qualif_const_arg(def)
-            } else {
-                mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id))
-            }
-        },
-        mir_const_qualif_const_arg: |tcx, (did, param_did)| {
-            mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
-        },
-        mir_promoted,
-        mir_drops_elaborated_and_const_checked,
-        mir_for_ctfe,
-        mir_for_ctfe_of_const_arg,
-        optimized_mir,
-        is_mir_available,
-        is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
-        promoted_mir: |tcx, def_id| {
-            let def_id = def_id.expect_local();
-            if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
-                tcx.promoted_mir_of_const_arg(def)
-            } else {
-                promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id))
-            }
-        },
-        promoted_mir_of_const_arg: |tcx, (did, param_did)| {
-            promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
-        },
-        ..*providers
-    };
-    coverage::query::provide(providers);
-}
-
-fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
-    let def_id = def_id.expect_local();
-    tcx.mir_keys(()).contains(&def_id)
-}
-
-/// Finds the full set of `DefId`s within the current crate that have
-/// MIR associated with them.
-fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxHashSet<LocalDefId> {
-    let mut set = FxHashSet::default();
-
-    // All body-owners have MIR associated with them.
-    set.extend(tcx.body_owners());
-
-    // Additionally, tuple struct/variant constructors have MIR, but
-    // they don't have a BodyId, so we need to build them separately.
-    struct GatherCtors<'a, 'tcx> {
-        tcx: TyCtxt<'tcx>,
-        set: &'a mut FxHashSet<LocalDefId>,
-    }
-    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
-        fn visit_variant_data(
-            &mut self,
-            v: &'tcx hir::VariantData<'tcx>,
-            _: Symbol,
-            _: &'tcx hir::Generics<'tcx>,
-            _: hir::HirId,
-            _: Span,
-        ) {
-            if let hir::VariantData::Tuple(_, hir_id) = *v {
-                self.set.insert(self.tcx.hir().local_def_id(hir_id));
-            }
-            intravisit::walk_struct_def(self, v)
-        }
-        type Map = intravisit::ErasedMap<'tcx>;
-        fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
-            NestedVisitorMap::None
-        }
-    }
-    tcx.hir()
-        .krate()
-        .visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
-
-    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> {
@@ -161,467 +24,3 @@ pub trait MirPass<'tcx> {
 
     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);
-
-    // No need to const-check a non-const `fn`.
-    if const_kind.is_none() {
-        return Default::default();
-    }
-
-    // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
-    // cannot yet be stolen), because `mir_promoted()`, which steals
-    // from `mir_const(), forces this query to execute before
-    // performing the steal.
-    let body = &tcx.mir_const(def).borrow();
-
-    if body.return_ty().references_error() {
-        tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
-        return Default::default();
-    }
-
-    let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) };
-
-    let mut validator = check_consts::check::Checker::new(&ccx);
-    validator.check_body();
-
-    // We return the qualifs in the return place for every MIR body, even though it is only used
-    // when deciding to promote a reference to a `const` for now.
-    validator.qualifs_in_return_place()
-}
-
-/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
-fn mir_const<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx Steal<Body<'tcx>> {
-    if let Some(def) = def.try_upgrade(tcx) {
-        return tcx.mir_const(def);
-    }
-
-    // Unsafety check uses the raw mir, so make sure it is run.
-    if !tcx.sess.opts.debugging_opts.thir_unsafeck {
-        if let Some(param_did) = def.const_param_did {
-            tcx.ensure().unsafety_check_result_for_const_arg((def.did, param_did));
-        } else {
-            tcx.ensure().unsafety_check_result(def.did);
-        }
-    }
-
-    let mut body = tcx.mir_built(def).steal();
-
-    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,
-            &function_item_references::FunctionItemReferences,
-            // What we need to do constant evaluation.
-            &simplify::SimplifyCfg::new("initial"),
-            &rustc_peek::SanityCheck,
-        ]],
-    );
-    tcx.alloc_steal_mir(body)
-}
-
-/// Compute the main MIR body and the list of MIR bodies of the promoteds.
-fn mir_promoted(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
-    if let Some(def) = def.try_upgrade(tcx) {
-        return tcx.mir_promoted(def);
-    }
-
-    // Ensure that we compute the `mir_const_qualif` for constants at
-    // this point, before we steal the mir-const result.
-    // Also this means promotion can rely on all const checks having been done.
-    let _ = tcx.mir_const_qualif_opt_const_arg(def);
-    let _ = tcx.mir_abstract_const_opt_const_arg(def.to_global());
-    let mut body = tcx.mir_const(def).steal();
-
-    let mut required_consts = Vec::new();
-    let mut required_consts_visitor = RequiredConstsVisitor::new(&mut required_consts);
-    for (bb, bb_data) in traversal::reverse_postorder(&body) {
-        required_consts_visitor.visit_basic_block_data(bb, bb_data);
-    }
-    body.required_consts = required_consts;
-
-    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.instrument_coverage() { &[&coverage::InstrumentCoverage] } else { &[] };
-
-    run_passes(tcx, &mut body, MirPhase::ConstPromotion, &[promote, opt_coverage]);
-
-    let promoted = promote_pass.promoted_fragments.into_inner();
-    (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
-}
-
-/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
-fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
-    let did = def_id.expect_local();
-    if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
-        tcx.mir_for_ctfe_of_const_arg(def)
-    } else {
-        tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
-    }
-}
-
-/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter.
-/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that
-/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
-/// the const parameter while type checking the main body, which in turn would try
-/// to type check the main body again.
-fn mir_for_ctfe_of_const_arg<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    (did, param_did): (LocalDefId, DefId),
-) -> &'tcx Body<'tcx> {
-    tcx.arena.alloc(inner_mir_for_ctfe(
-        tcx,
-        ty::WithOptConstParam { did, const_param_did: Some(param_did) },
-    ))
-}
-
-fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
-    // FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
-    if tcx.is_constructor(def.did.to_def_id()) {
-        // There's no reason to run all of the MIR passes on constructors when
-        // we can just output the MIR we want directly. This also saves const
-        // qualification and borrow checking the trouble of special casing
-        // constructors.
-        return shim::build_adt_ctor(tcx, def.did.to_def_id());
-    }
-
-    let context = tcx
-        .hir()
-        .body_const_context(def.did)
-        .expect("mir_for_ctfe should not be used for runtime functions");
-
-    let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
-
-    match context {
-        // Do not const prop functions, either they get executed at runtime or exported to metadata,
-        // so we run const prop on them, or they don't, in which case we const evaluate some control
-        // flow paths of the function and any errors in those paths will get emitted as const eval
-        // errors.
-        hir::ConstContext::ConstFn => {}
-        // Static items always get evaluated, so we can just let const eval see if any erroneous
-        // control flow paths get executed.
-        hir::ConstContext::Static(_) => {}
-        // Associated constants get const prop run so we detect common failure situations in the
-        // crate that defined the constant.
-        // Technically we want to not run on regular const items, but oli-obk doesn't know how to
-        // conveniently detect that at this point without looking at the HIR.
-        hir::ConstContext::Const => {
-            #[rustfmt::skip]
-            let optimizations: &[&dyn MirPass<'_>] = &[
-                &const_prop::ConstProp,
-            ];
-
-            #[rustfmt::skip]
-            run_passes(
-                tcx,
-                &mut body,
-                MirPhase::Optimization,
-                &[
-                    optimizations,
-                ],
-            );
-        }
-    }
-
-    debug_assert!(!body.has_free_regions(tcx), "Free regions in MIR for CTFE");
-
-    body
-}
-
-/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
-/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
-/// end up missing the source MIR due to stealing happening.
-fn mir_drops_elaborated_and_const_checked<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx Steal<Body<'tcx>> {
-    if let Some(def) = def.try_upgrade(tcx) {
-        return tcx.mir_drops_elaborated_and_const_checked(def);
-    }
-
-    // (Mir-)Borrowck uses `mir_promoted`, so we have to force it to
-    // execute before we can steal.
-    if let Some(param_did) = def.const_param_did {
-        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
-    } else {
-        tcx.ensure().mir_borrowck(def.did);
-    }
-
-    let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
-    use rustc_middle::hir::map::blocks::FnLikeNode;
-    let is_fn_like = FnLikeNode::from_node(tcx.hir().get(hir_id)).is_some();
-    if is_fn_like {
-        let did = def.did.to_def_id();
-        let def = ty::WithOptConstParam::unknown(did);
-
-        // Do not compute the mir call graph without said call graph actually being used.
-        if inline::is_enabled(tcx) {
-            let _ = tcx.mir_inliner_callees(ty::InstanceDef::Item(def));
-        }
-    }
-
-    let (body, _) = tcx.mir_promoted(def);
-    let mut body = body.steal();
-
-    run_post_borrowck_cleanup_passes(tcx, &mut body);
-    check_consts::post_drop_elaboration::check_live_drops(tcx, &body);
-    tcx.alloc_steal_mir(body)
-}
-
-/// After this series of passes, no lifetime analysis based on borrowing can be done.
-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>] = &[
-        // Remove all things only needed by analysis
-        &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,
-        // This will remove extraneous landing pads which are no longer
-        // necessary as well as well as forcing any call in a non-unwinding
-        // function calling a possibly-unwinding function to abort the process.
-        &abort_unwinding_calls::AbortUnwindingCalls,
-        // AddMovesForPackedDrops needs to run after drop
-        // elaboration.
-        &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,
-        &lower_intrinsics::LowerIntrinsics,
-        &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]);
-}
-
-fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let mir_opt_level = tcx.sess.mir_opt_level();
-
-    // 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>] = &[
-        &lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
-        &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_storage_markers::RemoveStorageMarkers,
-        &remove_zsts::RemoveZsts,
-        &const_goto::ConstGoto,
-        &remove_unneeded_drops::RemoveUnneededDrops,
-        &match_branches::MatchBranchSimplification,
-        // inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
-        &multiple_return_terminators::MultipleReturnTerminators,
-        &instcombine::InstCombine,
-        &separate_const_switch::SeparateConstSwitch,
-        &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,
-        &simplify_branches::SimplifyBranches::new("final"),
-        &remove_noop_landing_pads::RemoveNoopLandingPads,
-        &simplify::SimplifyCfg::new("final"),
-        &nrvo::RenameReturnPlace,
-        &const_debuginfo::ConstDebugInfo,
-        &simplify::SimplifyLocals,
-        &multiple_return_terminators::MultipleReturnTerminators,
-        &deduplicate_blocks::DeduplicateBlocks,
-    ];
-
-    // 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,
-    ];
-
-    // Some cleanup necessary at least for LLVM and potentially other codegen backends.
-    let pre_codegen_cleanup: &[&dyn MirPass<'tcx>] = &[
-        &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,
-        ],
-    );
-}
-
-/// Optimize the MIR and prepare it for codegen.
-fn optimized_mir<'tcx>(tcx: TyCtxt<'tcx>, did: DefId) -> &'tcx Body<'tcx> {
-    let did = did.expect_local();
-    assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
-    tcx.arena.alloc(inner_optimized_mir(tcx, did))
-}
-
-fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
-    if tcx.is_constructor(did.to_def_id()) {
-        // There's no reason to run all of the MIR passes on constructors when
-        // we can just output the MIR we want directly. This also saves const
-        // qualification and borrow checking the trouble of special casing
-        // constructors.
-        return shim::build_adt_ctor(tcx, did.to_def_id());
-    }
-
-    match tcx.hir().body_const_context(did) {
-        // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked`
-        // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it
-        // computes and caches its result.
-        Some(hir::ConstContext::ConstFn) => tcx.ensure().mir_for_ctfe(did),
-        None => {}
-        Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
-    }
-    let mut body =
-        tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
-    run_optimization_passes(tcx, &mut body);
-
-    debug_assert!(!body.has_free_regions(tcx), "Free regions in optimized MIR");
-
-    body
-}
-
-/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
-/// constant evaluation once all substitutions become known.
-fn promoted_mir<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    def: ty::WithOptConstParam<LocalDefId>,
-) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
-    if tcx.is_constructor(def.did.to_def_id()) {
-        return tcx.arena.alloc(IndexVec::new());
-    }
-
-    if let Some(param_did) = def.const_param_did {
-        tcx.ensure().mir_borrowck_const_arg((def.did, param_did));
-    } else {
-        tcx.ensure().mir_borrowck(def.did);
-    }
-    let (_, promoted) = tcx.mir_promoted(def);
-    let mut promoted = promoted.steal();
-
-    for body in &mut promoted {
-        run_post_borrowck_cleanup_passes(tcx, body);
-    }
-
-    debug_assert!(!promoted.has_free_regions(tcx), "Free regions in promoted MIR");
-
-    tcx.arena.alloc(promoted)
-}
diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
deleted file mode 100644
index cd2db180552..00000000000
--- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-//! This pass removes jumps to basic blocks containing only a return, and replaces them with a
-//! return instead.
-
-use crate::transform::{simplify, MirPass};
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::*;
-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.mir_opt_level() < 4 {
-            return;
-        }
-
-        // find basic blocks with no statement and a return terminator
-        let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len());
-        let def_id = body.source.def_id();
-        let bbs = body.basic_blocks_mut();
-        for idx in bbs.indices() {
-            if bbs[idx].statements.is_empty()
-                && bbs[idx].terminator().kind == TerminatorKind::Return
-            {
-                bbs_simple_returns.insert(idx);
-            }
-        }
-
-        for bb in bbs {
-            if !tcx.consider_optimizing(|| format!("MultipleReturnTerminators {:?} ", def_id)) {
-                break;
-            }
-
-            if let TerminatorKind::Goto { target } = bb.terminator().kind {
-                if bbs_simple_returns.contains(target) {
-                    bb.terminator_mut().kind = TerminatorKind::Return;
-                }
-            }
-        }
-
-        simplify::remove_dead_blocks(tcx, body)
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs
deleted file mode 100644
index 445dc12909c..00000000000
--- a/compiler/rustc_mir/src/transform/nrvo.rs
+++ /dev/null
@@ -1,239 +0,0 @@
-//! See the docs for [`RenameReturnPlace`].
-
-use rustc_hir::Mutability;
-use rustc_index::bit_set::HybridBitSet;
-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;
-
-/// 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`.
-///
-/// This allows LLVM to perform an optimization similar to the named return value optimization
-/// (NRVO) that is guaranteed in C++. This avoids a stack allocation and `memcpy` for the
-/// relatively common pattern of allocating a buffer on the stack, mutating it, and returning it by
-/// value like so:
-///
-/// ```rust
-/// fn foo(init: fn(&mut [u8; 1024])) -> [u8; 1024] {
-///     let mut buf = [0; 1024];
-///     init(&mut buf);
-///     buf
-/// }
-/// ```
-///
-/// For now, this pass is very simple and only capable of eliminating a single copy. A more general
-/// version of copy propagation, such as the one based on non-overlapping live ranges in [#47954] and
-/// [#71003], could yield even more benefits.
-///
-/// [#47954]: https://github.com/rust-lang/rust/pull/47954
-/// [#71003]: https://github.com/rust-lang/rust/pull/71003
-pub struct RenameReturnPlace;
-
-impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
-        if tcx.sess.mir_opt_level() == 0 {
-            return;
-        }
-
-        let def_id = body.source.def_id();
-        let returned_local = match local_eligible_for_nrvo(body) {
-            Some(l) => l,
-            None => {
-                debug!("`{:?}` was ineligible for NRVO", def_id);
-                return;
-            }
-        };
-
-        if !tcx.consider_optimizing(|| format!("RenameReturnPlace {:?}", def_id)) {
-            return;
-        }
-
-        debug!(
-            "`{:?}` was eligible for NRVO, making {:?} the return place",
-            def_id, returned_local
-        );
-
-        RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body(body);
-
-        // Clean up the `NOP`s we inserted for statements made useless by our renaming.
-        for block_data in body.basic_blocks_mut() {
-            block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop);
-        }
-
-        // Overwrite the debuginfo of `_0` with that of the renamed local.
-        let (renamed_decl, ret_decl) =
-            body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE);
-
-        // Sometimes, the return place is assigned a local of a different but coercable type, for
-        // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means
-        // its type may no longer match the return type of its function. This doesn't cause a
-        // problem in codegen because these two types are layout-compatible, but may be unexpected.
-        debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty);
-        ret_decl.clone_from(renamed_decl);
-
-        // The return place is always mutable.
-        ret_decl.mutability = Mutability::Mut;
-    }
-}
-
-/// MIR that is eligible for the NRVO must fulfill two conditions:
-///   1. The return place must not be read prior to the `Return` terminator.
-///   2. A simple assignment of a whole local to the return place (e.g., `_0 = _1`) must be the
-///      only definition of the return place reaching the `Return` terminator.
-///
-/// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned
-/// to the return place along all possible paths through the control-flow graph.
-fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
-    if IsReturnPlaceRead::run(body) {
-        return None;
-    }
-
-    let mut copied_to_return_place = None;
-    for block in body.basic_blocks().indices() {
-        // Look for blocks with a `Return` terminator.
-        if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) {
-            continue;
-        }
-
-        // Look for an assignment of a single local to the return place prior to the `Return`.
-        let returned_local = find_local_assigned_to_return_place(block, body)?;
-        match body.local_kind(returned_local) {
-            // FIXME: Can we do this for arguments as well?
-            mir::LocalKind::Arg => return None,
-
-            mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"),
-            mir::LocalKind::Var | mir::LocalKind::Temp => {}
-        }
-
-        // If multiple different locals are copied to the return place. We can't pick a
-        // single one to rename.
-        if copied_to_return_place.map_or(false, |old| old != returned_local) {
-            return None;
-        }
-
-        copied_to_return_place = Some(returned_local);
-    }
-
-    copied_to_return_place
-}
-
-fn find_local_assigned_to_return_place(
-    start: BasicBlock,
-    body: &mut mir::Body<'_>,
-) -> Option<Local> {
-    let mut block = start;
-    let mut seen = HybridBitSet::new_empty(body.basic_blocks().len());
-
-    // Iterate as long as `block` has exactly one predecessor that we have not yet visited.
-    while seen.insert(block) {
-        trace!("Looking for assignments to `_0` in {:?}", block);
-
-        let local = body[block].statements.iter().rev().find_map(as_local_assigned_to_return_place);
-        if local.is_some() {
-            return local;
-        }
-
-        match body.predecessors()[block].as_slice() {
-            &[pred] => block = pred,
-            _ => return None,
-        }
-    }
-
-    None
-}
-
-// If this statement is an assignment of an unprojected local to the return place,
-// return that local.
-fn as_local_assigned_to_return_place(stmt: &mir::Statement<'_>) -> Option<Local> {
-    if let mir::StatementKind::Assign(box (lhs, rhs)) = &stmt.kind {
-        if lhs.as_local() == Some(mir::RETURN_PLACE) {
-            if let mir::Rvalue::Use(mir::Operand::Copy(rhs) | mir::Operand::Move(rhs)) = rhs {
-                return rhs.as_local();
-            }
-        }
-    }
-
-    None
-}
-
-struct RenameToReturnPlace<'tcx> {
-    to_rename: Local,
-    tcx: TyCtxt<'tcx>,
-}
-
-/// Replaces all uses of `self.to_rename` with `_0`.
-impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_statement(&mut self, stmt: &mut mir::Statement<'tcx>, loc: Location) {
-        // Remove assignments of the local being replaced to the return place, since it is now the
-        // return place:
-        //     _0 = _1
-        if as_local_assigned_to_return_place(stmt) == Some(self.to_rename) {
-            stmt.kind = mir::StatementKind::Nop;
-            return;
-        }
-
-        // Remove storage annotations for the local being replaced:
-        //     StorageLive(_1)
-        if let mir::StatementKind::StorageLive(local) | mir::StatementKind::StorageDead(local) =
-            stmt.kind
-        {
-            if local == self.to_rename {
-                stmt.kind = mir::StatementKind::Nop;
-                return;
-            }
-        }
-
-        self.super_statement(stmt, loc)
-    }
-
-    fn visit_terminator(&mut self, terminator: &mut mir::Terminator<'tcx>, loc: Location) {
-        // Ignore the implicit "use" of the return place in a `Return` statement.
-        if let mir::TerminatorKind::Return = terminator.kind {
-            return;
-        }
-
-        self.super_terminator(terminator, loc);
-    }
-
-    fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) {
-        if *l == mir::RETURN_PLACE {
-            assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo));
-        } else if *l == self.to_rename {
-            *l = mir::RETURN_PLACE;
-        }
-    }
-}
-
-struct IsReturnPlaceRead(bool);
-
-impl IsReturnPlaceRead {
-    fn run(body: &mir::Body<'_>) -> bool {
-        let mut vis = IsReturnPlaceRead(false);
-        vis.visit_body(body);
-        vis.0
-    }
-}
-
-impl Visitor<'tcx> for IsReturnPlaceRead {
-    fn visit_local(&mut self, &l: &Local, ctxt: PlaceContext, _: Location) {
-        if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() {
-            self.0 = true;
-        }
-    }
-
-    fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, loc: Location) {
-        // Ignore the implicit "use" of the return place in a `Return` statement.
-        if let mir::TerminatorKind::Return = terminator.kind {
-            return;
-        }
-
-        self.super_terminator(terminator, loc);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
deleted file mode 100644
index 5347846a4b3..00000000000
--- a/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-use crate::transform::MirPass;
-use crate::util::patch::MirPatch;
-use rustc_index::bit_set::BitSet;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use rustc_target::spec::PanicStrategy;
-
-/// A pass that removes noop landing pads and replaces jumps to them with
-/// `None`. This is important because otherwise LLVM generates terrible
-/// code for these.
-pub struct RemoveNoopLandingPads;
-
-pub fn remove_noop_landing_pads<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    if tcx.sess.panic_strategy() == PanicStrategy::Abort {
-        return;
-    }
-    debug!("remove_noop_landing_pads({:?})", body);
-
-    RemoveNoopLandingPads.remove_nop_landing_pads(body)
-}
-
-impl<'tcx> MirPass<'tcx> for RemoveNoopLandingPads {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        remove_noop_landing_pads(tcx, body);
-    }
-}
-
-impl RemoveNoopLandingPads {
-    fn is_nop_landing_pad(
-        &self,
-        bb: BasicBlock,
-        body: &Body<'_>,
-        nop_landing_pads: &BitSet<BasicBlock>,
-    ) -> bool {
-        for stmt in &body[bb].statements {
-            match &stmt.kind {
-                StatementKind::FakeRead(..)
-                | StatementKind::StorageLive(_)
-                | StatementKind::StorageDead(_)
-                | StatementKind::AscribeUserType(..)
-                | StatementKind::Coverage(..)
-                | StatementKind::Nop => {
-                    // These are all nops in a landing pad
-                }
-
-                StatementKind::Assign(box (place, Rvalue::Use(_) | Rvalue::Discriminant(_))) => {
-                    if place.as_local().is_some() {
-                        // Writing to a local (e.g., a drop flag) does not
-                        // turn a landing pad to a non-nop
-                    } else {
-                        return false;
-                    }
-                }
-
-                StatementKind::Assign { .. }
-                | StatementKind::SetDiscriminant { .. }
-                | StatementKind::LlvmInlineAsm { .. }
-                | StatementKind::CopyNonOverlapping(..)
-                | StatementKind::Retag { .. } => {
-                    return false;
-                }
-            }
-        }
-
-        let terminator = body[bb].terminator();
-        match terminator.kind {
-            TerminatorKind::Goto { .. }
-            | TerminatorKind::Resume
-            | TerminatorKind::SwitchInt { .. }
-            | TerminatorKind::FalseEdge { .. }
-            | TerminatorKind::FalseUnwind { .. } => {
-                terminator.successors().all(|&succ| nop_landing_pads.contains(succ))
-            }
-            TerminatorKind::GeneratorDrop
-            | TerminatorKind::Yield { .. }
-            | TerminatorKind::Return
-            | TerminatorKind::Abort
-            | TerminatorKind::Unreachable
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::InlineAsm { .. } => false,
-        }
-    }
-
-    fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
-        // make sure there's a single resume block
-        let resume_block = {
-            let patch = MirPatch::new(body);
-            let resume_block = patch.resume_block();
-            patch.apply(body);
-            resume_block
-        };
-        debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
-
-        let mut jumps_folded = 0;
-        let mut landing_pads_removed = 0;
-        let mut nop_landing_pads = BitSet::new_empty(body.basic_blocks().len());
-
-        // This is a post-order traversal, so that if A post-dominates B
-        // then A will be visited before B.
-        let postorder: Vec<_> = traversal::postorder(body).map(|(bb, _)| bb).collect();
-        for bb in postorder {
-            debug!("  processing {:?}", bb);
-            if let Some(unwind) = body[bb].terminator_mut().unwind_mut() {
-                if let Some(unwind_bb) = *unwind {
-                    if nop_landing_pads.contains(unwind_bb) {
-                        debug!("    removing noop landing pad");
-                        landing_pads_removed += 1;
-                        *unwind = None;
-                    }
-                }
-            }
-
-            for target in body[bb].terminator_mut().successors_mut() {
-                if *target != resume_block && nop_landing_pads.contains(*target) {
-                    debug!("    folding noop jump to {:?} to resume block", target);
-                    *target = resume_block;
-                    jumps_folded += 1;
-                }
-            }
-
-            let is_nop_landing_pad = self.is_nop_landing_pad(bb, body, &nop_landing_pads);
-            if is_nop_landing_pad {
-                nop_landing_pads.insert(bb);
-            }
-            debug!("    is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
-        }
-
-        debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/remove_storage_markers.rs b/compiler/rustc_mir/src/transform/remove_storage_markers.rs
deleted file mode 100644
index 2d529feb072..00000000000
--- a/compiler/rustc_mir/src/transform/remove_storage_markers.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-//! This pass removes storage markers if they won't be emitted during codegen.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-pub struct RemoveStorageMarkers;
-
-impl<'tcx> MirPass<'tcx> for RemoveStorageMarkers {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.emit_lifetime_markers() {
-            return;
-        }
-
-        trace!("Running RemoveStorageMarkers on {:?}", body.source);
-        for data in body.basic_blocks_mut() {
-            data.statements.retain(|statement| match statement.kind {
-                StatementKind::StorageLive(..)
-                | StatementKind::StorageDead(..)
-                | StatementKind::Nop => false,
-                _ => true,
-            })
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
deleted file mode 100644
index 02e45021a0a..00000000000
--- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-//! This pass replaces a drop of a type that does not need dropping, with a goto
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-use super::simplify::simplify_cfg;
-
-pub struct RemoveUnneededDrops;
-
-impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running RemoveUnneededDrops on {:?}", body.source);
-
-        let did = body.source.def_id();
-        let param_env = tcx.param_env(did);
-        let mut should_simplify = false;
-
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks {
-            let terminator = block.terminator_mut();
-            if let TerminatorKind::Drop { place, target, .. } = terminator.kind {
-                let ty = place.ty(local_decls, tcx);
-                if ty.ty.needs_drop(tcx, param_env) {
-                    continue;
-                }
-                if !tcx.consider_optimizing(|| format!("RemoveUnneededDrops {:?} ", did)) {
-                    continue;
-                }
-                debug!("SUCCESS: replacing `drop` with goto({:?})", target);
-                terminator.kind = TerminatorKind::Goto { target };
-                should_simplify = true;
-            }
-        }
-
-        // if we applied optimizations, we potentially have some cfg to cleanup to
-        // make it easier for further passes
-        if should_simplify {
-            simplify_cfg(tcx, body);
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs
deleted file mode 100644
index 03277b1b2e0..00000000000
--- a/compiler/rustc_mir/src/transform/remove_zsts.rs
+++ /dev/null
@@ -1,76 +0,0 @@
-//! Removes assignments to ZST places.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::tcx::PlaceTy;
-use rustc_middle::mir::{Body, LocalDecls, Place, StatementKind};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct RemoveZsts;
-
-impl<'tcx> MirPass<'tcx> for RemoveZsts {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(body.source.def_id());
-        let (basic_blocks, local_decls) = body.basic_blocks_and_local_decls_mut();
-        for block in basic_blocks.iter_mut() {
-            for statement in block.statements.iter_mut() {
-                if let StatementKind::Assign(box (place, _)) = statement.kind {
-                    let place_ty = place.ty(local_decls, tcx).ty;
-                    if !maybe_zst(place_ty) {
-                        continue;
-                    }
-                    let layout = match tcx.layout_of(param_env.and(place_ty)) {
-                        Ok(layout) => layout,
-                        Err(_) => continue,
-                    };
-                    if !layout.is_zst() {
-                        continue;
-                    }
-                    if involves_a_union(place, local_decls, tcx) {
-                        continue;
-                    }
-                    if tcx.consider_optimizing(|| {
-                        format!(
-                            "RemoveZsts - Place: {:?} SourceInfo: {:?}",
-                            place, statement.source_info
-                        )
-                    }) {
-                        statement.make_nop();
-                    }
-                }
-            }
-        }
-    }
-}
-
-/// A cheap, approximate check to avoid unnecessary `layout_of` calls.
-fn maybe_zst(ty: Ty<'_>) -> bool {
-    match ty.kind() {
-        // maybe ZST (could be more precise)
-        ty::Adt(..) | ty::Array(..) | ty::Closure(..) | ty::Tuple(..) | ty::Opaque(..) => true,
-        // definitely ZST
-        ty::FnDef(..) | ty::Never => true,
-        // unreachable or can't be ZST
-        _ => false,
-    }
-}
-
-/// Miri lazily allocates memory for locals on assignment,
-/// so we must preserve writes to unions and union fields,
-/// or it will ICE on reads of those fields.
-fn involves_a_union<'tcx>(
-    place: Place<'tcx>,
-    local_decls: &LocalDecls<'tcx>,
-    tcx: TyCtxt<'tcx>,
-) -> bool {
-    let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
-    if place_ty.ty.is_union() {
-        return true;
-    }
-    for elem in place.projection {
-        place_ty = place_ty.projection_ty(tcx, elem);
-        if place_ty.ty.is_union() {
-            return true;
-        }
-    }
-    return false;
-}
diff --git a/compiler/rustc_mir/src/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs
deleted file mode 100644
index 8b64ad65ab3..00000000000
--- a/compiler/rustc_mir/src/transform/required_consts.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-use rustc_middle::mir::visit::Visitor;
-use rustc_middle::mir::{Constant, Location};
-use rustc_middle::ty::ConstKind;
-
-pub struct RequiredConstsVisitor<'a, 'tcx> {
-    required_consts: &'a mut Vec<Constant<'tcx>>,
-}
-
-impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
-    pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self {
-        RequiredConstsVisitor { required_consts }
-    }
-}
-
-impl<'a, 'tcx> Visitor<'tcx> for RequiredConstsVisitor<'a, 'tcx> {
-    fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
-        if let Some(ct) = constant.literal.const_for_ty() {
-            if let ConstKind::Unevaluated(_) = ct.val {
-                self.required_consts.push(*constant);
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/separate_const_switch.rs b/compiler/rustc_mir/src/transform/separate_const_switch.rs
deleted file mode 100644
index 87cd27984a0..00000000000
--- a/compiler/rustc_mir/src/transform/separate_const_switch.rs
+++ /dev/null
@@ -1,343 +0,0 @@
-//! A pass that duplicates switch-terminated blocks
-//! into a new copy for each predecessor, provided
-//! the predecessor sets the value being switched
-//! over to a constant.
-//!
-//! The purpose of this pass is to help constant
-//! propagation passes to simplify the switch terminator
-//! of the copied blocks into gotos when some predecessors
-//! statically determine the output of switches.
-//!
-//! ```text
-//!     x = 12 ---              ---> something
-//!               \            / 12
-//!                --> switch x
-//!               /            \ otherwise
-//!     x = y  ---              ---> something else
-//! ```
-//! becomes
-//! ```text
-//!     x = 12 ---> switch x ------> something
-//!                          \ / 12
-//!                           X
-//!                          / \ otherwise
-//!     x = y  ---> switch x ------> something else
-//! ```
-//! so it can hopefully later be turned by another pass into
-//! ```text
-//!     x = 12 --------------------> something
-//!                            / 12
-//!                           /
-//!                          /   otherwise
-//!     x = y  ---- switch x ------> something else
-//! ```
-//!
-//! This optimization is meant to cover simple cases
-//! like `?` desugaring. For now, it thus focuses on
-//! simplicity rather than completeness (it notably
-//! sometimes duplicates abusively).
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use smallvec::SmallVec;
-
-pub struct SeparateConstSwitch;
-
-impl<'tcx> MirPass<'tcx> for SeparateConstSwitch {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            return;
-        }
-
-        // If execution did something, applying a simplification layer
-        // helps later passes optimize the copy away.
-        if separate_const_switch(body) > 0 {
-            super::simplify::simplify_cfg(tcx, body);
-        }
-    }
-}
-
-/// Returns the amount of blocks that were duplicated
-pub fn separate_const_switch<'tcx>(body: &mut Body<'tcx>) -> usize {
-    let mut new_blocks: SmallVec<[(BasicBlock, BasicBlock); 6]> = SmallVec::new();
-    let predecessors = body.predecessors();
-    'block_iter: for (block_id, block) in body.basic_blocks().iter_enumerated() {
-        if let TerminatorKind::SwitchInt {
-            discr: Operand::Copy(switch_place) | Operand::Move(switch_place),
-            ..
-        } = block.terminator().kind
-        {
-            // If the block is on an unwind path, do not
-            // apply the optimization as unwind paths
-            // rely on a unique parent invariant
-            if block.is_cleanup {
-                continue 'block_iter;
-            }
-
-            // If the block has fewer than 2 predecessors, ignore it
-            // we could maybe chain blocks that have exactly one
-            // predecessor, but for now we ignore that
-            if predecessors[block_id].len() < 2 {
-                continue 'block_iter;
-            }
-
-            // First, let's find a non-const place
-            // that determines the result of the switch
-            if let Some(switch_place) = find_determining_place(switch_place, block) {
-                // We now have an input place for which it would
-                // be interesting if predecessors assigned it from a const
-
-                let mut predecessors_left = predecessors[block_id].len();
-                'predec_iter: for predecessor_id in predecessors[block_id].iter().copied() {
-                    let predecessor = &body.basic_blocks()[predecessor_id];
-
-                    // First we make sure the predecessor jumps
-                    // in a reasonable way
-                    match &predecessor.terminator().kind {
-                        // The following terminators are
-                        // unconditionally valid
-                        TerminatorKind::Goto { .. } | TerminatorKind::SwitchInt { .. } => {}
-
-                        TerminatorKind::FalseEdge { real_target, .. } => {
-                            if *real_target != block_id {
-                                continue 'predec_iter;
-                            }
-                        }
-
-                        // The following terminators are not allowed
-                        TerminatorKind::Resume
-                        | TerminatorKind::Drop { .. }
-                        | TerminatorKind::DropAndReplace { .. }
-                        | TerminatorKind::Call { .. }
-                        | TerminatorKind::Assert { .. }
-                        | TerminatorKind::FalseUnwind { .. }
-                        | TerminatorKind::Yield { .. }
-                        | TerminatorKind::Abort
-                        | TerminatorKind::Return
-                        | TerminatorKind::Unreachable
-                        | TerminatorKind::InlineAsm { .. }
-                        | TerminatorKind::GeneratorDrop => {
-                            continue 'predec_iter;
-                        }
-                    }
-
-                    if is_likely_const(switch_place, predecessor) {
-                        new_blocks.push((predecessor_id, block_id));
-                        predecessors_left -= 1;
-                        if predecessors_left < 2 {
-                            // If the original block only has one predecessor left,
-                            // we have nothing left to do
-                            break 'predec_iter;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // Once the analysis is done, perform the duplication
-    let body_span = body.span;
-    let copied_blocks = new_blocks.len();
-    let blocks = body.basic_blocks_mut();
-    for (pred_id, target_id) in new_blocks {
-        let new_block = blocks[target_id].clone();
-        let new_block_id = blocks.push(new_block);
-        let terminator = blocks[pred_id].terminator_mut();
-
-        match terminator.kind {
-            TerminatorKind::Goto { ref mut target } => {
-                *target = new_block_id;
-            }
-
-            TerminatorKind::FalseEdge { ref mut real_target, .. } => {
-                if *real_target == target_id {
-                    *real_target = new_block_id;
-                }
-            }
-
-            TerminatorKind::SwitchInt { ref mut targets, .. } => {
-                targets.all_targets_mut().iter_mut().for_each(|x| {
-                    if *x == target_id {
-                        *x = new_block_id;
-                    }
-                });
-            }
-
-            TerminatorKind::Resume
-            | TerminatorKind::Abort
-            | TerminatorKind::Return
-            | TerminatorKind::Unreachable
-            | TerminatorKind::GeneratorDrop
-            | TerminatorKind::Assert { .. }
-            | TerminatorKind::DropAndReplace { .. }
-            | TerminatorKind::FalseUnwind { .. }
-            | TerminatorKind::Drop { .. }
-            | TerminatorKind::Call { .. }
-            | TerminatorKind::InlineAsm { .. }
-            | TerminatorKind::Yield { .. } => {
-                span_bug!(
-                    body_span,
-                    "basic block terminator had unexpected kind {:?}",
-                    &terminator.kind
-                )
-            }
-        }
-    }
-
-    copied_blocks
-}
-
-/// This function describes a rough heuristic guessing
-/// whether a place is last set with a const within the block.
-/// Notably, it will be overly pessimistic in cases that are already
-/// not handled by `separate_const_switch`.
-fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<'tcx>) -> bool {
-    for statement in block.statements.iter().rev() {
-        match &statement.kind {
-            StatementKind::Assign(assign) => {
-                if assign.0 == tracked_place {
-                    match assign.1 {
-                        // These rvalues are definitely constant
-                        Rvalue::Use(Operand::Constant(_))
-                        | Rvalue::Ref(_, _, _)
-                        | Rvalue::AddressOf(_, _)
-                        | Rvalue::Cast(_, Operand::Constant(_), _)
-                        | Rvalue::NullaryOp(_, _)
-                        | Rvalue::UnaryOp(_, Operand::Constant(_)) => return true,
-
-                        // These rvalues make things ambiguous
-                        Rvalue::Repeat(_, _)
-                        | Rvalue::ThreadLocalRef(_)
-                        | Rvalue::Len(_)
-                        | Rvalue::BinaryOp(_, _)
-                        | Rvalue::CheckedBinaryOp(_, _)
-                        | Rvalue::Aggregate(_, _) => return false,
-
-                        // These rvalues move the place to track
-                        Rvalue::Cast(_, Operand::Copy(place) | Operand::Move(place), _)
-                        | Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
-                        | Rvalue::UnaryOp(_, Operand::Copy(place) | Operand::Move(place))
-                        | Rvalue::Discriminant(place) => tracked_place = place,
-                    }
-                }
-            }
-
-            // If the discriminant is set, it is always set
-            // as a constant, so the job is done.
-            // As we are **ignoring projections**, if the place
-            // we are tracking sees its discriminant be set,
-            // that means we had to be tracking the discriminant
-            // specifically (as it is impossible to switch over
-            // an enum directly, and if we were switching over
-            // its content, we would have had to at least cast it to
-            // some variant first)
-            StatementKind::SetDiscriminant { place, .. } => {
-                if **place == tracked_place {
-                    return true;
-                }
-            }
-
-            // If inline assembly is found, we probably should
-            // not try to analyze the code
-            StatementKind::LlvmInlineAsm(_) => return false,
-
-            // These statements have no influence on the place
-            // we are interested in
-            StatementKind::FakeRead(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::Retag(_, _)
-            | StatementKind::AscribeUserType(_, _)
-            | StatementKind::Coverage(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::CopyNonOverlapping(_)
-            | StatementKind::Nop => {}
-        }
-    }
-
-    // If no good reason for the place to be const is found,
-    // give up. We could maybe go up predecessors, but in
-    // most cases giving up now should be sufficient.
-    false
-}
-
-/// Finds a unique place that entirely determines the value
-/// of `switch_place`, if it exists. This is only a heuristic.
-/// Ideally we would like to track multiple determining places
-/// for some edge cases, but one is enough for a lot of situations.
-fn find_determining_place<'tcx>(
-    mut switch_place: Place<'tcx>,
-    block: &BasicBlockData<'tcx>,
-) -> Option<Place<'tcx>> {
-    for statement in block.statements.iter().rev() {
-        match &statement.kind {
-            StatementKind::Assign(op) => {
-                if op.0 != switch_place {
-                    continue;
-                }
-
-                match op.1 {
-                    // The following rvalues move the place
-                    // that may be const in the predecessor
-                    Rvalue::Use(Operand::Move(new) | Operand::Copy(new))
-                    | Rvalue::UnaryOp(_, Operand::Copy(new) | Operand::Move(new))
-                    | Rvalue::Cast(_, Operand::Move(new) | Operand::Copy(new), _)
-                    | Rvalue::Repeat(Operand::Move(new) | Operand::Copy(new), _)
-                    | Rvalue::Discriminant(new)
-                    => switch_place = new,
-
-                    // The following rvalues might still make the block
-                    // be valid but for now we reject them
-                    Rvalue::Len(_)
-                    | Rvalue::Ref(_, _, _)
-                    | Rvalue::BinaryOp(_, _)
-                    | Rvalue::CheckedBinaryOp(_, _)
-                    | Rvalue::Aggregate(_, _)
-
-                    // The following rvalues definitely mean we cannot
-                    // or should not apply this optimization
-                    | Rvalue::Use(Operand::Constant(_))
-                    | Rvalue::Repeat(Operand::Constant(_), _)
-                    | Rvalue::ThreadLocalRef(_)
-                    | Rvalue::AddressOf(_, _)
-                    | Rvalue::NullaryOp(_, _)
-                    | Rvalue::UnaryOp(_, Operand::Constant(_))
-                    | Rvalue::Cast(_, Operand::Constant(_), _)
-                    => return None,
-                }
-            }
-
-            // These statements have no influence on the place
-            // we are interested in
-            StatementKind::FakeRead(_)
-            | StatementKind::StorageLive(_)
-            | StatementKind::StorageDead(_)
-            | StatementKind::Retag(_, _)
-            | StatementKind::AscribeUserType(_, _)
-            | StatementKind::Coverage(_)
-            | StatementKind::CopyNonOverlapping(_)
-            | StatementKind::Nop => {}
-
-            // If inline assembly is found, we probably should
-            // not try to analyze the code
-            StatementKind::LlvmInlineAsm(_) => return None,
-
-            // If the discriminant is set, it is always set
-            // as a constant, so the job is already done.
-            // As we are **ignoring projections**, if the place
-            // we are tracking sees its discriminant be set,
-            // that means we had to be tracking the discriminant
-            // specifically (as it is impossible to switch over
-            // an enum directly, and if we were switching over
-            // its content, we would have had to at least cast it to
-            // some variant first)
-            StatementKind::SetDiscriminant { place, .. } => {
-                if **place == switch_place {
-                    return None;
-                }
-            }
-        }
-    }
-
-    Some(switch_place)
-}
diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs
deleted file mode 100644
index 3ecb5133e3b..00000000000
--- a/compiler/rustc_mir/src/transform/simplify.rs
+++ /dev/null
@@ -1,592 +0,0 @@
-//! A number of passes which remove various redundancies in the CFG.
-//!
-//! The `SimplifyCfg` pass gets rid of unnecessary blocks in the CFG, whereas the `SimplifyLocals`
-//! gets rid of all the unnecessary local variable declarations.
-//!
-//! The `SimplifyLocals` pass is kinda expensive and therefore not very suitable to be run often.
-//! Most of the passes should not care or be impacted in meaningful ways due to extra locals
-//! either, so running the pass once, right before codegen, should suffice.
-//!
-//! On the other side of the spectrum, the `SimplifyCfg` pass is considerably cheap to run, thus
-//! one should run it after every pass which may modify CFG in significant ways. This pass must
-//! also be run before any analysis passes because it removes dead blocks, and some of these can be
-//! ill-typed.
-//!
-//! The cause of this typing issue is typeck allowing most blocks whose end is not reachable have
-//! an arbitrary return type, rather than having the usual () return type (as a note, typeck's
-//! notion of reachability is in fact slightly weaker than MIR CFG reachability - see #31617). A
-//! standard example of the situation is:
-//!
-//! ```rust
-//!   fn example() {
-//!       let _a: char = { return; };
-//!   }
-//! ```
-//!
-//! Here the block (`{ return; }`) has the return type `char`, rather than `()`, but the MIR we
-//! naively generate still contains the `_a = ()` write in the unreachable block "after" the
-//! return.
-
-use crate::transform::MirPass;
-use rustc_index::vec::{Idx, IndexVec};
-use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-use smallvec::SmallVec;
-use std::borrow::Cow;
-use std::convert::TryInto;
-
-pub struct SimplifyCfg {
-    label: String,
-}
-
-impl SimplifyCfg {
-    pub fn new(label: &str) -> Self {
-        SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
-    }
-}
-
-pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
-    CfgSimplifier::new(body).simplify();
-    remove_dead_blocks(tcx, body);
-
-    // FIXME: Should probably be moved into some kind of pass manager
-    body.basic_blocks_mut().raw.shrink_to_fit();
-}
-
-impl<'tcx> MirPass<'tcx> for SimplifyCfg {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(&self.label)
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
-        simplify_cfg(tcx, body);
-    }
-}
-
-pub struct CfgSimplifier<'a, 'tcx> {
-    basic_blocks: &'a mut IndexVec<BasicBlock, BasicBlockData<'tcx>>,
-    pred_count: IndexVec<BasicBlock, u32>,
-}
-
-impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
-    pub fn new(body: &'a mut Body<'tcx>) -> Self {
-        let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
-
-        // we can't use mir.predecessors() here because that counts
-        // dead blocks, which we don't want to.
-        pred_count[START_BLOCK] = 1;
-
-        for (_, data) in traversal::preorder(body) {
-            if let Some(ref term) = data.terminator {
-                for &tgt in term.successors() {
-                    pred_count[tgt] += 1;
-                }
-            }
-        }
-
-        let basic_blocks = body.basic_blocks_mut();
-
-        CfgSimplifier { basic_blocks, pred_count }
-    }
-
-    pub fn simplify(mut self) {
-        self.strip_nops();
-
-        let mut start = START_BLOCK;
-
-        // Vec of the blocks that should be merged. We store the indices here, instead of the
-        // statements itself to avoid moving the (relatively) large statements twice.
-        // We do not push the statements directly into the target block (`bb`) as that is slower
-        // due to additional reallocations
-        let mut merged_blocks = Vec::new();
-        loop {
-            let mut changed = false;
-
-            self.collapse_goto_chain(&mut start, &mut changed);
-
-            for bb in self.basic_blocks.indices() {
-                if self.pred_count[bb] == 0 {
-                    continue;
-                }
-
-                debug!("simplifying {:?}", bb);
-
-                let mut terminator =
-                    self.basic_blocks[bb].terminator.take().expect("invalid terminator state");
-
-                for successor in terminator.successors_mut() {
-                    self.collapse_goto_chain(successor, &mut changed);
-                }
-
-                let mut inner_changed = true;
-                merged_blocks.clear();
-                while inner_changed {
-                    inner_changed = false;
-                    inner_changed |= self.simplify_branch(&mut terminator);
-                    inner_changed |= self.merge_successor(&mut merged_blocks, &mut terminator);
-                    changed |= inner_changed;
-                }
-
-                let statements_to_merge =
-                    merged_blocks.iter().map(|&i| self.basic_blocks[i].statements.len()).sum();
-
-                if statements_to_merge > 0 {
-                    let mut statements = std::mem::take(&mut self.basic_blocks[bb].statements);
-                    statements.reserve(statements_to_merge);
-                    for &from in &merged_blocks {
-                        statements.append(&mut self.basic_blocks[from].statements);
-                    }
-                    self.basic_blocks[bb].statements = statements;
-                }
-
-                self.basic_blocks[bb].terminator = Some(terminator);
-            }
-
-            if !changed {
-                break;
-            }
-        }
-
-        if start != START_BLOCK {
-            debug_assert!(self.pred_count[START_BLOCK] == 0);
-            self.basic_blocks.swap(START_BLOCK, start);
-            self.pred_count.swap(START_BLOCK, start);
-
-            // pred_count == 1 if the start block has no predecessor _blocks_.
-            if self.pred_count[START_BLOCK] > 1 {
-                for (bb, data) in self.basic_blocks.iter_enumerated_mut() {
-                    if self.pred_count[bb] == 0 {
-                        continue;
-                    }
-
-                    for target in data.terminator_mut().successors_mut() {
-                        if *target == start {
-                            *target = START_BLOCK;
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /// This function will return `None` if
-    /// * the block has statements
-    /// * the block has a terminator other than `goto`
-    /// * the block has no terminator (meaning some other part of the current optimization stole it)
-    fn take_terminator_if_simple_goto(&mut self, bb: BasicBlock) -> Option<Terminator<'tcx>> {
-        match self.basic_blocks[bb] {
-            BasicBlockData {
-                ref statements,
-                terminator:
-                    ref mut terminator @ Some(Terminator { kind: TerminatorKind::Goto { .. }, .. }),
-                ..
-            } if statements.is_empty() => terminator.take(),
-            // if `terminator` is None, this means we are in a loop. In that
-            // case, let all the loop collapse to its entry.
-            _ => None,
-        }
-    }
-
-    /// Collapse a goto chain starting from `start`
-    fn collapse_goto_chain(&mut self, start: &mut BasicBlock, changed: &mut bool) {
-        // Using `SmallVec` here, because in some logs on libcore oli-obk saw many single-element
-        // goto chains. We should probably benchmark different sizes.
-        let mut terminators: SmallVec<[_; 1]> = Default::default();
-        let mut current = *start;
-        while let Some(terminator) = self.take_terminator_if_simple_goto(current) {
-            let target = match terminator {
-                Terminator { kind: TerminatorKind::Goto { target }, .. } => target,
-                _ => unreachable!(),
-            };
-            terminators.push((current, terminator));
-            current = target;
-        }
-        let last = current;
-        *start = last;
-        while let Some((current, mut terminator)) = terminators.pop() {
-            let target = match terminator {
-                Terminator { kind: TerminatorKind::Goto { ref mut target }, .. } => target,
-                _ => unreachable!(),
-            };
-            *changed |= *target != last;
-            *target = last;
-            debug!("collapsing goto chain from {:?} to {:?}", current, target);
-
-            if self.pred_count[current] == 1 {
-                // This is the last reference to current, so the pred-count to
-                // to target is moved into the current block.
-                self.pred_count[current] = 0;
-            } else {
-                self.pred_count[*target] += 1;
-                self.pred_count[current] -= 1;
-            }
-            self.basic_blocks[current].terminator = Some(terminator);
-        }
-    }
-
-    // merge a block with 1 `goto` predecessor to its parent
-    fn merge_successor(
-        &mut self,
-        merged_blocks: &mut Vec<BasicBlock>,
-        terminator: &mut Terminator<'tcx>,
-    ) -> bool {
-        let target = match terminator.kind {
-            TerminatorKind::Goto { target } if self.pred_count[target] == 1 => target,
-            _ => return false,
-        };
-
-        debug!("merging block {:?} into {:?}", target, terminator);
-        *terminator = match self.basic_blocks[target].terminator.take() {
-            Some(terminator) => terminator,
-            None => {
-                // unreachable loop - this should not be possible, as we
-                // don't strand blocks, but handle it correctly.
-                return false;
-            }
-        };
-
-        merged_blocks.push(target);
-        self.pred_count[target] = 0;
-
-        true
-    }
-
-    // turn a branch with all successors identical to a goto
-    fn simplify_branch(&mut self, terminator: &mut Terminator<'tcx>) -> bool {
-        match terminator.kind {
-            TerminatorKind::SwitchInt { .. } => {}
-            _ => return false,
-        };
-
-        let first_succ = {
-            if let Some(&first_succ) = terminator.successors().next() {
-                if terminator.successors().all(|s| *s == first_succ) {
-                    let count = terminator.successors().count();
-                    self.pred_count[first_succ] -= (count - 1) as u32;
-                    first_succ
-                } else {
-                    return false;
-                }
-            } else {
-                return false;
-            }
-        };
-
-        debug!("simplifying branch {:?}", terminator);
-        terminator.kind = TerminatorKind::Goto { target: first_succ };
-        true
-    }
-
-    fn strip_nops(&mut self) {
-        for blk in self.basic_blocks.iter_mut() {
-            blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop))
-        }
-    }
-}
-
-pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) {
-    let reachable = traversal::reachable_as_bitset(body);
-    let num_blocks = body.basic_blocks().len();
-    if num_blocks == reachable.count() {
-        return;
-    }
-
-    let basic_blocks = body.basic_blocks_mut();
-    let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
-    let mut used_blocks = 0;
-    for alive_index in reachable.iter() {
-        let alive_index = alive_index.index();
-        replacements[alive_index] = BasicBlock::new(used_blocks);
-        if alive_index != used_blocks {
-            // Swap the next alive block data with the current available slot. Since
-            // alive_index is non-decreasing this is a valid operation.
-            basic_blocks.raw.swap(alive_index, used_blocks);
-        }
-        used_blocks += 1;
-    }
-
-    if tcx.sess.instrument_coverage() {
-        save_unreachable_coverage(basic_blocks, used_blocks);
-    }
-
-    basic_blocks.raw.truncate(used_blocks);
-
-    for block in basic_blocks {
-        for target in block.terminator_mut().successors_mut() {
-            *target = replacements[target.index()];
-        }
-    }
-}
-
-/// Some MIR transforms can determine at compile time that a sequences of
-/// statements will never be executed, so they can be dropped from the MIR.
-/// For example, an `if` or `else` block that is guaranteed to never be executed
-/// because its condition can be evaluated at compile time, such as by const
-/// evaluation: `if false { ... }`.
-///
-/// Those statements are bypassed by redirecting paths in the CFG around the
-/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually
-/// include `Coverage` statements representing the Rust source code regions to
-/// be counted at runtime. Without these `Coverage` statements, the regions are
-/// lost, and the Rust source code will show no coverage information.
-///
-/// What we want to show in a coverage report is the dead code with coverage
-/// counts of `0`. To do this, we need to save the code regions, by injecting
-/// `Unreachable` coverage statements. These are non-executable statements whose
-/// code regions are still recorded in the coverage map, representing regions
-/// with `0` executions.
-fn save_unreachable_coverage(
-    basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>,
-    first_dead_block: usize,
-) {
-    let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| {
-        live_block.statements.iter().any(|statement| {
-            if let StatementKind::Coverage(coverage) = &statement.kind {
-                matches!(coverage.kind, CoverageKind::Counter { .. })
-            } else {
-                false
-            }
-        })
-    });
-    if !has_live_counters {
-        // If there are no live `Counter` `Coverage` statements anymore, don't
-        // move dead coverage to the `START_BLOCK`. Just allow the dead
-        // `Coverage` statements to be dropped with the dead blocks.
-        //
-        // The `generator::StateTransform` MIR pass can create atypical
-        // conditions, where all live `Counter`s are dropped from the MIR.
-        //
-        // At least one Counter per function is required by LLVM (and necessary,
-        // to add the `function_hash` to the counter's call to the LLVM
-        // intrinsic `instrprof.increment()`).
-        return;
-    }
-
-    // Retain coverage info for dead blocks, so coverage reports will still
-    // report `0` executions for the uncovered code regions.
-    let mut dropped_coverage = Vec::new();
-    for dead_block in basic_blocks.raw[first_dead_block..].iter() {
-        for statement in dead_block.statements.iter() {
-            if let StatementKind::Coverage(coverage) = &statement.kind {
-                if let Some(code_region) = &coverage.code_region {
-                    dropped_coverage.push((statement.source_info, code_region.clone()));
-                }
-            }
-        }
-    }
-
-    let start_block = &mut basic_blocks[START_BLOCK];
-    for (source_info, code_region) in dropped_coverage {
-        start_block.statements.push(Statement {
-            source_info,
-            kind: StatementKind::Coverage(Box::new(Coverage {
-                kind: CoverageKind::Unreachable,
-                code_region: Some(code_region),
-            })),
-        })
-    }
-}
-
-pub struct SimplifyLocals;
-
-impl<'tcx> MirPass<'tcx> for SimplifyLocals {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("running SimplifyLocals on {:?}", body.source);
-        simplify_locals(body, tcx);
-    }
-}
-
-pub fn simplify_locals<'tcx>(body: &mut Body<'tcx>, tcx: TyCtxt<'tcx>) {
-    // First, we're going to get a count of *actual* uses for every `Local`.
-    let mut used_locals = UsedLocals::new(body);
-
-    // Next, we're going to remove any `Local` with zero actual uses. When we remove those
-    // `Locals`, we're also going to subtract any uses of other `Locals` from the `used_locals`
-    // count. For example, if we removed `_2 = discriminant(_1)`, then we'll subtract one from
-    // `use_counts[_1]`. That in turn might make `_1` unused, so we loop until we hit a
-    // fixedpoint where there are no more unused locals.
-    remove_unused_definitions(&mut used_locals, body);
-
-    // Finally, we'll actually do the work of shrinking `body.local_decls` and remapping the `Local`s.
-    let map = make_local_map(&mut body.local_decls, &used_locals);
-
-    // Only bother running the `LocalUpdater` if we actually found locals to remove.
-    if map.iter().any(Option::is_none) {
-        // Update references to all vars and tmps now
-        let mut updater = LocalUpdater { map, tcx };
-        updater.visit_body(body);
-
-        body.local_decls.shrink_to_fit();
-    }
-}
-
-/// Construct the mapping while swapping out unused stuff out from the `vec`.
-fn make_local_map<V>(
-    local_decls: &mut IndexVec<Local, V>,
-    used_locals: &UsedLocals,
-) -> IndexVec<Local, Option<Local>> {
-    let mut map: IndexVec<Local, Option<Local>> = IndexVec::from_elem(None, &*local_decls);
-    let mut used = Local::new(0);
-
-    for alive_index in local_decls.indices() {
-        // `is_used` treats the `RETURN_PLACE` and arguments as used.
-        if !used_locals.is_used(alive_index) {
-            continue;
-        }
-
-        map[alive_index] = Some(used);
-        if alive_index != used {
-            local_decls.swap(alive_index, used);
-        }
-        used.increment_by(1);
-    }
-    local_decls.truncate(used.index());
-    map
-}
-
-/// Keeps track of used & unused locals.
-struct UsedLocals {
-    increment: bool,
-    arg_count: u32,
-    use_count: IndexVec<Local, u32>,
-}
-
-impl UsedLocals {
-    /// Determines which locals are used & unused in the given body.
-    fn new(body: &Body<'_>) -> Self {
-        let mut this = Self {
-            increment: true,
-            arg_count: body.arg_count.try_into().unwrap(),
-            use_count: IndexVec::from_elem(0, &body.local_decls),
-        };
-        this.visit_body(body);
-        this
-    }
-
-    /// Checks if local is used.
-    ///
-    /// Return place and arguments are always considered used.
-    fn is_used(&self, local: Local) -> bool {
-        trace!("is_used({:?}): use_count: {:?}", local, self.use_count[local]);
-        local.as_u32() <= self.arg_count || self.use_count[local] != 0
-    }
-
-    /// Updates the use counts to reflect the removal of given statement.
-    fn statement_removed(&mut self, statement: &Statement<'tcx>) {
-        self.increment = false;
-
-        // The location of the statement is irrelevant.
-        let location = Location { block: START_BLOCK, statement_index: 0 };
-        self.visit_statement(statement, location);
-    }
-
-    /// Visits a left-hand side of an assignment.
-    fn visit_lhs(&mut self, place: &Place<'tcx>, location: Location) {
-        if place.is_indirect() {
-            // A use, not a definition.
-            self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), location);
-        } else {
-            // A definition. The base local itself is not visited, so this occurrence is not counted
-            // toward its use count. There might be other locals still, used in an indexing
-            // projection.
-            self.super_projection(
-                place.as_ref(),
-                PlaceContext::MutatingUse(MutatingUseContext::Projection),
-                location,
-            );
-        }
-    }
-}
-
-impl Visitor<'_> for UsedLocals {
-    fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
-        match statement.kind {
-            StatementKind::LlvmInlineAsm(..)
-            | StatementKind::CopyNonOverlapping(..)
-            | StatementKind::Retag(..)
-            | StatementKind::Coverage(..)
-            | StatementKind::FakeRead(..)
-            | StatementKind::AscribeUserType(..) => {
-                self.super_statement(statement, location);
-            }
-
-            StatementKind::Nop => {}
-
-            StatementKind::StorageLive(_local) | StatementKind::StorageDead(_local) => {}
-
-            StatementKind::Assign(box (ref place, ref rvalue)) => {
-                self.visit_lhs(place, location);
-                self.visit_rvalue(rvalue, location);
-            }
-
-            StatementKind::SetDiscriminant { ref place, variant_index: _ } => {
-                self.visit_lhs(place, location);
-            }
-        }
-    }
-
-    fn visit_local(&mut self, local: &Local, _ctx: PlaceContext, _location: Location) {
-        if self.increment {
-            self.use_count[*local] += 1;
-        } else {
-            assert_ne!(self.use_count[*local], 0);
-            self.use_count[*local] -= 1;
-        }
-    }
-}
-
-/// Removes unused definitions. Updates the used locals to reflect the changes made.
-fn remove_unused_definitions<'a, 'tcx>(used_locals: &'a mut UsedLocals, body: &mut Body<'tcx>) {
-    // The use counts are updated as we remove the statements. A local might become unused
-    // during the retain operation, leading to a temporary inconsistency (storage statements or
-    // definitions referencing the local might remain). For correctness it is crucial that this
-    // computation reaches a fixed point.
-
-    let mut modified = true;
-    while modified {
-        modified = false;
-
-        for data in body.basic_blocks_mut() {
-            // Remove unnecessary StorageLive and StorageDead annotations.
-            data.statements.retain(|statement| {
-                let keep = match &statement.kind {
-                    StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
-                        used_locals.is_used(*local)
-                    }
-                    StatementKind::Assign(box (place, _)) => used_locals.is_used(place.local),
-
-                    StatementKind::SetDiscriminant { ref place, .. } => {
-                        used_locals.is_used(place.local)
-                    }
-                    _ => true,
-                };
-
-                if !keep {
-                    trace!("removing statement {:?}", statement);
-                    modified = true;
-                    used_locals.statement_removed(statement);
-                }
-
-                keep
-            });
-        }
-    }
-}
-
-struct LocalUpdater<'tcx> {
-    map: IndexVec<Local, Option<Local>>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'tcx> MutVisitor<'tcx> for LocalUpdater<'tcx> {
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.tcx
-    }
-
-    fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) {
-        *l = self.map[*l].unwrap();
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs
deleted file mode 100644
index a9a45e61a38..00000000000
--- a/compiler/rustc_mir/src/transform/simplify_branches.rs
+++ /dev/null
@@ -1,66 +0,0 @@
-//! A pass that simplifies branches when their condition is known.
-
-use crate::transform::MirPass;
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-use std::borrow::Cow;
-
-pub struct SimplifyBranches {
-    label: String,
-}
-
-impl SimplifyBranches {
-    pub fn new(label: &str) -> Self {
-        SimplifyBranches { label: format!("SimplifyBranches-{}", label) }
-    }
-}
-
-impl<'tcx> MirPass<'tcx> for SimplifyBranches {
-    fn name(&self) -> Cow<'_, str> {
-        Cow::Borrowed(&self.label)
-    }
-
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        let param_env = tcx.param_env(body.source.def_id());
-        for block in body.basic_blocks_mut() {
-            let terminator = block.terminator_mut();
-            terminator.kind = match terminator.kind {
-                TerminatorKind::SwitchInt {
-                    discr: Operand::Constant(ref c),
-                    switch_ty,
-                    ref targets,
-                    ..
-                } => {
-                    let constant = c.literal.try_eval_bits(tcx, param_env, switch_ty);
-                    if let Some(constant) = constant {
-                        let otherwise = targets.otherwise();
-                        let mut ret = TerminatorKind::Goto { target: otherwise };
-                        for (v, t) in targets.iter() {
-                            if v == constant {
-                                ret = TerminatorKind::Goto { target: t };
-                                break;
-                            }
-                        }
-                        ret
-                    } else {
-                        continue;
-                    }
-                }
-                TerminatorKind::Assert {
-                    target, cond: Operand::Constant(ref c), expected, ..
-                } => match c.literal.try_eval_bool(tcx, param_env) {
-                    Some(v) if v == expected => TerminatorKind::Goto { target },
-                    _ => continue,
-                },
-                TerminatorKind::FalseEdge { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-                TerminatorKind::FalseUnwind { real_target, .. } => {
-                    TerminatorKind::Goto { target: real_target }
-                }
-                _ => continue,
-            };
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
deleted file mode 100644
index 948fcd9f455..00000000000
--- a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs
+++ /dev/null
@@ -1,238 +0,0 @@
-use std::iter;
-
-use super::MirPass;
-use rustc_middle::{
-    mir::{
-        interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
-        StatementKind, SwitchTargets, TerminatorKind,
-    },
-    ty::{Ty, TyCtxt},
-};
-
-/// Pass to convert `if` conditions on integrals into switches on the integral.
-/// For an example, it turns something like
-///
-/// ```
-/// _3 = Eq(move _4, const 43i32);
-/// StorageDead(_4);
-/// switchInt(_3) -> [false: bb2, otherwise: bb3];
-/// ```
-///
-/// into:
-///
-/// ```
-/// switchInt(_4) -> [43i32: bb3, otherwise: bb2];
-/// ```
-pub struct SimplifyComparisonIntegral;
-
-impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running SimplifyComparisonIntegral on {:?}", body.source);
-
-        let helper = OptimizationFinder { body };
-        let opts = helper.find_optimizations();
-        let mut storage_deads_to_insert = vec![];
-        let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
-        let param_env = tcx.param_env(body.source.def_id());
-        for opt in opts {
-            trace!("SUCCESS: Applying {:?}", opt);
-            // replace terminator with a switchInt that switches on the integer directly
-            let bbs = &mut body.basic_blocks_mut();
-            let bb = &mut bbs[opt.bb_idx];
-            let new_value = match opt.branch_value_scalar {
-                Scalar::Int(int) => {
-                    let layout = tcx
-                        .layout_of(param_env.and(opt.branch_value_ty))
-                        .expect("if we have an evaluated constant we must know the layout");
-                    int.assert_bits(layout.size)
-                }
-                Scalar::Ptr(..) => continue,
-            };
-            const FALSE: u128 = 0;
-
-            let mut new_targets = opt.targets;
-            let first_value = new_targets.iter().next().unwrap().0;
-            let first_is_false_target = first_value == FALSE;
-            match opt.op {
-                BinOp::Eq => {
-                    // if the assignment was Eq we want the true case to be first
-                    if first_is_false_target {
-                        new_targets.all_targets_mut().swap(0, 1);
-                    }
-                }
-                BinOp::Ne => {
-                    // if the assignment was Ne we want the false case to be first
-                    if !first_is_false_target {
-                        new_targets.all_targets_mut().swap(0, 1);
-                    }
-                }
-                _ => unreachable!(),
-            }
-
-            // delete comparison statement if it the value being switched on was moved, which means it can not be user later on
-            if opt.can_remove_bin_op_stmt {
-                bb.statements[opt.bin_op_stmt_idx].make_nop();
-            } else {
-                // if the integer being compared to a const integral is being moved into the comparison,
-                // e.g `_2 = Eq(move _3, const 'x');`
-                // we want to avoid making a double move later on in the switchInt on _3.
-                // So to avoid `switchInt(move _3) -> ['x': bb2, otherwise: bb1];`,
-                // we convert the move in the comparison statement to a copy.
-
-                // unwrap is safe as we know this statement is an assign
-                let (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap();
-
-                use Operand::*;
-                match rhs {
-                    Rvalue::BinaryOp(_, box (ref mut left @ Move(_), Constant(_))) => {
-                        *left = Copy(opt.to_switch_on);
-                    }
-                    Rvalue::BinaryOp(_, box (Constant(_), ref mut right @ Move(_))) => {
-                        *right = Copy(opt.to_switch_on);
-                    }
-                    _ => (),
-                }
-            }
-
-            let terminator = bb.terminator();
-
-            // remove StorageDead (if it exists) being used in the assign of the comparison
-            for (stmt_idx, stmt) in bb.statements.iter().enumerate() {
-                if !matches!(stmt.kind, StatementKind::StorageDead(local) if local == opt.to_switch_on.local)
-                {
-                    continue;
-                }
-                storage_deads_to_remove.push((stmt_idx, opt.bb_idx));
-                // if we have StorageDeads to remove then make sure to insert them at the top of each target
-                for bb_idx in new_targets.all_targets() {
-                    storage_deads_to_insert.push((
-                        *bb_idx,
-                        Statement {
-                            source_info: terminator.source_info,
-                            kind: StatementKind::StorageDead(opt.to_switch_on.local),
-                        },
-                    ));
-                }
-            }
-
-            let [bb_cond, bb_otherwise] = match new_targets.all_targets() {
-                [a, b] => [*a, *b],
-                e => bug!("expected 2 switch targets, got: {:?}", e),
-            };
-
-            let targets = SwitchTargets::new(iter::once((new_value, bb_cond)), bb_otherwise);
-
-            let terminator = bb.terminator_mut();
-            terminator.kind = TerminatorKind::SwitchInt {
-                discr: Operand::Move(opt.to_switch_on),
-                switch_ty: opt.branch_value_ty,
-                targets,
-            };
-        }
-
-        for (idx, bb_idx) in storage_deads_to_remove {
-            body.basic_blocks_mut()[bb_idx].statements[idx].make_nop();
-        }
-
-        for (idx, stmt) in storage_deads_to_insert {
-            body.basic_blocks_mut()[idx].statements.insert(0, stmt);
-        }
-    }
-}
-
-struct OptimizationFinder<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-}
-
-impl<'a, 'tcx> OptimizationFinder<'a, 'tcx> {
-    fn find_optimizations(&self) -> Vec<OptimizationInfo<'tcx>> {
-        self.body
-            .basic_blocks()
-            .iter_enumerated()
-            .filter_map(|(bb_idx, bb)| {
-                // find switch
-                let (place_switched_on, targets, place_switched_on_moved) =
-                    match &bb.terminator().kind {
-                        rustc_middle::mir::TerminatorKind::SwitchInt { discr, targets, .. } => {
-                            Some((discr.place()?, targets, discr.is_move()))
-                        }
-                        _ => None,
-                    }?;
-
-                // find the statement that assigns the place being switched on
-                bb.statements.iter().enumerate().rev().find_map(|(stmt_idx, stmt)| {
-                    match &stmt.kind {
-                        rustc_middle::mir::StatementKind::Assign(box (lhs, rhs))
-                            if *lhs == place_switched_on =>
-                        {
-                            match rhs {
-                                Rvalue::BinaryOp(
-                                    op @ (BinOp::Eq | BinOp::Ne),
-                                    box (left, right),
-                                ) => {
-                                    let (branch_value_scalar, branch_value_ty, to_switch_on) =
-                                        find_branch_value_info(left, right)?;
-
-                                    Some(OptimizationInfo {
-                                        bin_op_stmt_idx: stmt_idx,
-                                        bb_idx,
-                                        can_remove_bin_op_stmt: place_switched_on_moved,
-                                        to_switch_on,
-                                        branch_value_scalar,
-                                        branch_value_ty,
-                                        op: *op,
-                                        targets: targets.clone(),
-                                    })
-                                }
-                                _ => None,
-                            }
-                        }
-                        _ => None,
-                    }
-                })
-            })
-            .collect()
-    }
-}
-
-fn find_branch_value_info<'tcx>(
-    left: &Operand<'tcx>,
-    right: &Operand<'tcx>,
-) -> Option<(Scalar, Ty<'tcx>, Place<'tcx>)> {
-    // check that either left or right is a constant.
-    // if any are, we can use the other to switch on, and the constant as a value in a switch
-    use Operand::*;
-    match (left, right) {
-        (Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on))
-        | (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => {
-            let branch_value_ty = branch_value.literal.ty();
-            // we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats
-            if !branch_value_ty.is_integral() && !branch_value_ty.is_char() {
-                return None;
-            };
-            let branch_value_scalar = branch_value.literal.try_to_scalar()?;
-            Some((branch_value_scalar, branch_value_ty, *to_switch_on))
-        }
-        _ => None,
-    }
-}
-
-#[derive(Debug)]
-struct OptimizationInfo<'tcx> {
-    /// Basic block to apply the optimization
-    bb_idx: BasicBlock,
-    /// Statement index of Eq/Ne assignment that can be removed. None if the assignment can not be removed - i.e the statement is used later on
-    bin_op_stmt_idx: usize,
-    /// Can remove Eq/Ne assignment
-    can_remove_bin_op_stmt: bool,
-    /// Place that needs to be switched on. This place is of type integral
-    to_switch_on: Place<'tcx>,
-    /// Constant to use in switch target value
-    branch_value_scalar: Scalar,
-    /// Type of the constant value
-    branch_value_ty: Ty<'tcx>,
-    /// Either Eq or Ne
-    op: BinOp,
-    /// Current targets used in the switch
-    targets: SwitchTargets,
-}
diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs
deleted file mode 100644
index 7c35dab694f..00000000000
--- a/compiler/rustc_mir/src/transform/simplify_try.rs
+++ /dev/null
@@ -1,795 +0,0 @@
-//! The general point of the optimizations provided here is to simplify something like:
-//!
-//! ```rust
-//! match x {
-//!     Ok(x) => Ok(x),
-//!     Err(x) => Err(x)
-//! }
-//! ```
-//!
-//! into just `x`.
-
-use crate::transform::{simplify, MirPass};
-use itertools::Itertools as _;
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
-use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::*;
-use rustc_middle::ty::{self, List, Ty, TyCtxt};
-use rustc_target::abi::VariantIdx;
-use std::iter::{once, Enumerate, Peekable};
-use std::slice::Iter;
-
-/// Simplifies arms of form `Variant(x) => Variant(x)` to just a move.
-///
-/// This is done by transforming basic blocks where the statements match:
-///
-/// ```rust
-/// _LOCAL_TMP = ((_LOCAL_1 as Variant ).FIELD: TY );
-/// _TMP_2 = _LOCAL_TMP;
-/// ((_LOCAL_0 as Variant).FIELD: TY) = move _TMP_2;
-/// discriminant(_LOCAL_0) = VAR_IDX;
-/// ```
-///
-/// into:
-///
-/// ```rust
-/// _LOCAL_0 = move _LOCAL_1
-/// ```
-pub struct SimplifyArmIdentity;
-
-#[derive(Debug)]
-struct ArmIdentityInfo<'tcx> {
-    /// Storage location for the variant's field
-    local_temp_0: Local,
-    /// Storage location holding the variant being read from
-    local_1: Local,
-    /// The variant field being read from
-    vf_s0: VarField<'tcx>,
-    /// Index of the statement which loads the variant being read
-    get_variant_field_stmt: usize,
-
-    /// Tracks each assignment to a temporary of the variant's field
-    field_tmp_assignments: Vec<(Local, Local)>,
-
-    /// Storage location holding the variant's field that was read from
-    local_tmp_s1: Local,
-    /// Storage location holding the enum that we are writing to
-    local_0: Local,
-    /// The variant field being written to
-    vf_s1: VarField<'tcx>,
-
-    /// Storage location that the discriminant is being written to
-    set_discr_local: Local,
-    /// The variant being written
-    set_discr_var_idx: VariantIdx,
-
-    /// Index of the statement that should be overwritten as a move
-    stmt_to_overwrite: usize,
-    /// SourceInfo for the new move
-    source_info: SourceInfo,
-
-    /// Indices of matching Storage{Live,Dead} statements encountered.
-    /// (StorageLive index,, StorageDead index, Local)
-    storage_stmts: Vec<(usize, usize, Local)>,
-
-    /// The statements that should be removed (turned into nops)
-    stmts_to_remove: Vec<usize>,
-
-    /// Indices of debug variables that need to be adjusted to point to
-    // `{local_0}.{dbg_projection}`.
-    dbg_info_to_adjust: Vec<usize>,
-
-    /// The projection used to rewrite debug info.
-    dbg_projection: &'tcx List<PlaceElem<'tcx>>,
-}
-
-fn get_arm_identity_info<'a, 'tcx>(
-    stmts: &'a [Statement<'tcx>],
-    locals_count: usize,
-    debug_info: &'a [VarDebugInfo<'tcx>],
-) -> Option<ArmIdentityInfo<'tcx>> {
-    // This can't possibly match unless there are at least 3 statements in the block
-    // so fail fast on tiny blocks.
-    if stmts.len() < 3 {
-        return None;
-    }
-
-    let mut tmp_assigns = Vec::new();
-    let mut nop_stmts = Vec::new();
-    let mut storage_stmts = Vec::new();
-    let mut storage_live_stmts = Vec::new();
-    let mut storage_dead_stmts = Vec::new();
-
-    type StmtIter<'a, 'tcx> = Peekable<Enumerate<Iter<'a, Statement<'tcx>>>>;
-
-    fn is_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
-        matches!(stmt.kind, StatementKind::StorageLive(_) | StatementKind::StorageDead(_))
-    }
-
-    /// Eats consecutive Statements which match `test`, performing the specified `action` for each.
-    /// The iterator `stmt_iter` is not advanced if none were matched.
-    fn try_eat<'a, 'tcx>(
-        stmt_iter: &mut StmtIter<'a, 'tcx>,
-        test: impl Fn(&'a Statement<'tcx>) -> bool,
-        mut action: impl FnMut(usize, &'a Statement<'tcx>),
-    ) {
-        while stmt_iter.peek().map_or(false, |(_, stmt)| test(stmt)) {
-            let (idx, stmt) = stmt_iter.next().unwrap();
-
-            action(idx, stmt);
-        }
-    }
-
-    /// Eats consecutive `StorageLive` and `StorageDead` Statements.
-    /// The iterator `stmt_iter` is not advanced if none were found.
-    fn try_eat_storage_stmts<'a, 'tcx>(
-        stmt_iter: &mut StmtIter<'a, 'tcx>,
-        storage_live_stmts: &mut Vec<(usize, Local)>,
-        storage_dead_stmts: &mut Vec<(usize, Local)>,
-    ) {
-        try_eat(stmt_iter, is_storage_stmt, |idx, stmt| {
-            if let StatementKind::StorageLive(l) = stmt.kind {
-                storage_live_stmts.push((idx, l));
-            } else if let StatementKind::StorageDead(l) = stmt.kind {
-                storage_dead_stmts.push((idx, l));
-            }
-        })
-    }
-
-    fn is_tmp_storage_stmt<'tcx>(stmt: &Statement<'tcx>) -> bool {
-        use rustc_middle::mir::StatementKind::Assign;
-        if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) = &stmt.kind {
-            place.as_local().is_some() && p.as_local().is_some()
-        } else {
-            false
-        }
-    }
-
-    /// Eats consecutive `Assign` Statements.
-    // The iterator `stmt_iter` is not advanced if none were found.
-    fn try_eat_assign_tmp_stmts<'a, 'tcx>(
-        stmt_iter: &mut StmtIter<'a, 'tcx>,
-        tmp_assigns: &mut Vec<(Local, Local)>,
-        nop_stmts: &mut Vec<usize>,
-    ) {
-        try_eat(stmt_iter, is_tmp_storage_stmt, |idx, stmt| {
-            use rustc_middle::mir::StatementKind::Assign;
-            if let Assign(box (place, Rvalue::Use(Operand::Copy(p) | Operand::Move(p)))) =
-                &stmt.kind
-            {
-                tmp_assigns.push((place.as_local().unwrap(), p.as_local().unwrap()));
-                nop_stmts.push(idx);
-            }
-        })
-    }
-
-    fn find_storage_live_dead_stmts_for_local<'tcx>(
-        local: Local,
-        stmts: &[Statement<'tcx>],
-    ) -> Option<(usize, usize)> {
-        trace!("looking for {:?}", local);
-        let mut storage_live_stmt = None;
-        let mut storage_dead_stmt = None;
-        for (idx, stmt) in stmts.iter().enumerate() {
-            if stmt.kind == StatementKind::StorageLive(local) {
-                storage_live_stmt = Some(idx);
-            } else if stmt.kind == StatementKind::StorageDead(local) {
-                storage_dead_stmt = Some(idx);
-            }
-        }
-
-        Some((storage_live_stmt?, storage_dead_stmt.unwrap_or(usize::MAX)))
-    }
-
-    // Try to match the expected MIR structure with the basic block we're processing.
-    // We want to see something that looks like:
-    // ```
-    // (StorageLive(_) | StorageDead(_));*
-    // _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
-    // (StorageLive(_) | StorageDead(_));*
-    // (tmp_n+1 = tmp_n);*
-    // (StorageLive(_) | StorageDead(_));*
-    // (tmp_n+1 = tmp_n);*
-    // ((LOCAL_FROM as Variant).FIELD: TY) = move tmp;
-    // discriminant(LOCAL_FROM) = VariantIdx;
-    // (StorageLive(_) | StorageDead(_));*
-    // ```
-    let mut stmt_iter = stmts.iter().enumerate().peekable();
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    let (get_variant_field_stmt, stmt) = stmt_iter.next()?;
-    let (local_tmp_s0, local_1, vf_s0, dbg_projection) = match_get_variant_field(stmt)?;
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    try_eat_assign_tmp_stmts(&mut stmt_iter, &mut tmp_assigns, &mut nop_stmts);
-
-    let (idx, stmt) = stmt_iter.next()?;
-    let (local_tmp_s1, local_0, vf_s1) = match_set_variant_field(stmt)?;
-    nop_stmts.push(idx);
-
-    let (idx, stmt) = stmt_iter.next()?;
-    let (set_discr_local, set_discr_var_idx) = match_set_discr(stmt)?;
-    let discr_stmt_source_info = stmt.source_info;
-    nop_stmts.push(idx);
-
-    try_eat_storage_stmts(&mut stmt_iter, &mut storage_live_stmts, &mut storage_dead_stmts);
-
-    for (live_idx, live_local) in storage_live_stmts {
-        if let Some(i) = storage_dead_stmts.iter().rposition(|(_, l)| *l == live_local) {
-            let (dead_idx, _) = storage_dead_stmts.swap_remove(i);
-            storage_stmts.push((live_idx, dead_idx, live_local));
-
-            if live_local == local_tmp_s0 {
-                nop_stmts.push(get_variant_field_stmt);
-            }
-        }
-    }
-    // We sort primitive usize here so we can use unstable sort
-    nop_stmts.sort_unstable();
-
-    // Use one of the statements we're going to discard between the point
-    // where the storage location for the variant field becomes live and
-    // is killed.
-    let (live_idx, dead_idx) = find_storage_live_dead_stmts_for_local(local_tmp_s0, stmts)?;
-    let stmt_to_overwrite =
-        nop_stmts.iter().find(|stmt_idx| live_idx < **stmt_idx && **stmt_idx < dead_idx);
-
-    let mut tmp_assigned_vars = BitSet::new_empty(locals_count);
-    for (l, r) in &tmp_assigns {
-        tmp_assigned_vars.insert(*l);
-        tmp_assigned_vars.insert(*r);
-    }
-
-    let dbg_info_to_adjust: Vec<_> = debug_info
-        .iter()
-        .enumerate()
-        .filter_map(|(i, var_info)| {
-            if let VarDebugInfoContents::Place(p) = var_info.value {
-                if tmp_assigned_vars.contains(p.local) {
-                    return Some(i);
-                }
-            }
-
-            None
-        })
-        .collect();
-
-    Some(ArmIdentityInfo {
-        local_temp_0: local_tmp_s0,
-        local_1,
-        vf_s0,
-        get_variant_field_stmt,
-        field_tmp_assignments: tmp_assigns,
-        local_tmp_s1,
-        local_0,
-        vf_s1,
-        set_discr_local,
-        set_discr_var_idx,
-        stmt_to_overwrite: *stmt_to_overwrite?,
-        source_info: discr_stmt_source_info,
-        storage_stmts,
-        stmts_to_remove: nop_stmts,
-        dbg_info_to_adjust,
-        dbg_projection,
-    })
-}
-
-fn optimization_applies<'tcx>(
-    opt_info: &ArmIdentityInfo<'tcx>,
-    local_decls: &IndexVec<Local, LocalDecl<'tcx>>,
-    local_uses: &IndexVec<Local, usize>,
-    var_debug_info: &[VarDebugInfo<'tcx>],
-) -> bool {
-    trace!("testing if optimization applies...");
-
-    // FIXME(wesleywiser): possibly relax this restriction?
-    if opt_info.local_0 == opt_info.local_1 {
-        trace!("NO: moving into ourselves");
-        return false;
-    } else if opt_info.vf_s0 != opt_info.vf_s1 {
-        trace!("NO: the field-and-variant information do not match");
-        return false;
-    } else if local_decls[opt_info.local_0].ty != local_decls[opt_info.local_1].ty {
-        // FIXME(Centril,oli-obk): possibly relax to same layout?
-        trace!("NO: source and target locals have different types");
-        return false;
-    } else if (opt_info.local_0, opt_info.vf_s0.var_idx)
-        != (opt_info.set_discr_local, opt_info.set_discr_var_idx)
-    {
-        trace!("NO: the discriminants do not match");
-        return false;
-    }
-
-    // Verify the assignment chain consists of the form b = a; c = b; d = c; etc...
-    if opt_info.field_tmp_assignments.is_empty() {
-        trace!("NO: no assignments found");
-        return false;
-    }
-    let mut last_assigned_to = opt_info.field_tmp_assignments[0].1;
-    let source_local = last_assigned_to;
-    for (l, r) in &opt_info.field_tmp_assignments {
-        if *r != last_assigned_to {
-            trace!("NO: found unexpected assignment {:?} = {:?}", l, r);
-            return false;
-        }
-
-        last_assigned_to = *l;
-    }
-
-    // Check that the first and last used locals are only used twice
-    // since they are of the form:
-    //
-    // ```
-    // _first = ((_x as Variant).n: ty);
-    // _n = _first;
-    // ...
-    // ((_y as Variant).n: ty) = _n;
-    // discriminant(_y) = z;
-    // ```
-    for (l, r) in &opt_info.field_tmp_assignments {
-        if local_uses[*l] != 2 {
-            warn!("NO: FAILED assignment chain local {:?} was used more than twice", l);
-            return false;
-        } else if local_uses[*r] != 2 {
-            warn!("NO: FAILED assignment chain local {:?} was used more than twice", r);
-            return false;
-        }
-    }
-
-    // Check that debug info only points to full Locals and not projections.
-    for dbg_idx in &opt_info.dbg_info_to_adjust {
-        let dbg_info = &var_debug_info[*dbg_idx];
-        if let VarDebugInfoContents::Place(p) = dbg_info.value {
-            if !p.projection.is_empty() {
-                trace!("NO: debug info for {:?} had a projection {:?}", dbg_info.name, p);
-                return false;
-            }
-        }
-    }
-
-    if source_local != opt_info.local_temp_0 {
-        trace!(
-            "NO: start of assignment chain does not match enum variant temp: {:?} != {:?}",
-            source_local,
-            opt_info.local_temp_0
-        );
-        return false;
-    } else if last_assigned_to != opt_info.local_tmp_s1 {
-        trace!(
-            "NO: end of assignemnt chain does not match written enum temp: {:?} != {:?}",
-            last_assigned_to,
-            opt_info.local_tmp_s1
-        );
-        return false;
-    }
-
-    trace!("SUCCESS: optimization applies!");
-    true
-}
-
-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;
-        }
-
-        let source = body.source;
-        trace!("running SimplifyArmIdentity on {:?}", source);
-
-        let local_uses = LocalUseCounter::get_local_uses(body);
-        let (basic_blocks, local_decls, debug_info) =
-            body.basic_blocks_local_decls_mut_and_var_debug_info();
-        for bb in basic_blocks {
-            if let Some(opt_info) =
-                get_arm_identity_info(&bb.statements, local_decls.len(), debug_info)
-            {
-                trace!("got opt_info = {:#?}", opt_info);
-                if !optimization_applies(&opt_info, local_decls, &local_uses, &debug_info) {
-                    debug!("optimization skipped for {:?}", source);
-                    continue;
-                }
-
-                // Also remove unused Storage{Live,Dead} statements which correspond
-                // to temps used previously.
-                for (live_idx, dead_idx, local) in &opt_info.storage_stmts {
-                    // The temporary that we've read the variant field into is scoped to this block,
-                    // so we can remove the assignment.
-                    if *local == opt_info.local_temp_0 {
-                        bb.statements[opt_info.get_variant_field_stmt].make_nop();
-                    }
-
-                    for (left, right) in &opt_info.field_tmp_assignments {
-                        if local == left || local == right {
-                            bb.statements[*live_idx].make_nop();
-                            bb.statements[*dead_idx].make_nop();
-                        }
-                    }
-                }
-
-                // Right shape; transform
-                for stmt_idx in opt_info.stmts_to_remove {
-                    bb.statements[stmt_idx].make_nop();
-                }
-
-                let stmt = &mut bb.statements[opt_info.stmt_to_overwrite];
-                stmt.source_info = opt_info.source_info;
-                stmt.kind = StatementKind::Assign(Box::new((
-                    opt_info.local_0.into(),
-                    Rvalue::Use(Operand::Move(opt_info.local_1.into())),
-                )));
-
-                bb.statements.retain(|stmt| stmt.kind != StatementKind::Nop);
-
-                // Fix the debug info to point to the right local
-                for dbg_index in opt_info.dbg_info_to_adjust {
-                    let dbg_info = &mut debug_info[dbg_index];
-                    assert!(
-                        matches!(dbg_info.value, VarDebugInfoContents::Place(_)),
-                        "value was not a Place"
-                    );
-                    if let VarDebugInfoContents::Place(p) = &mut dbg_info.value {
-                        assert!(p.projection.is_empty());
-                        p.local = opt_info.local_0;
-                        p.projection = opt_info.dbg_projection;
-                    }
-                }
-
-                trace!("block is now {:?}", bb.statements);
-            }
-        }
-    }
-}
-
-struct LocalUseCounter {
-    local_uses: IndexVec<Local, usize>,
-}
-
-impl LocalUseCounter {
-    fn get_local_uses<'tcx>(body: &Body<'tcx>) -> IndexVec<Local, usize> {
-        let mut counter = LocalUseCounter { local_uses: IndexVec::from_elem(0, &body.local_decls) };
-        counter.visit_body(body);
-        counter.local_uses
-    }
-}
-
-impl<'tcx> Visitor<'tcx> for LocalUseCounter {
-    fn visit_local(&mut self, local: &Local, context: PlaceContext, _location: Location) {
-        if context.is_storage_marker()
-            || context == PlaceContext::NonUse(NonUseContext::VarDebugInfo)
-        {
-            return;
-        }
-
-        self.local_uses[*local] += 1;
-    }
-}
-
-/// Match on:
-/// ```rust
-/// _LOCAL_INTO = ((_LOCAL_FROM as Variant).FIELD: TY);
-/// ```
-fn match_get_variant_field<'tcx>(
-    stmt: &Statement<'tcx>,
-) -> Option<(Local, Local, VarField<'tcx>, &'tcx List<PlaceElem<'tcx>>)> {
-    match &stmt.kind {
-        StatementKind::Assign(box (
-            place_into,
-            Rvalue::Use(Operand::Copy(pf) | Operand::Move(pf)),
-        )) => {
-            let local_into = place_into.as_local()?;
-            let (local_from, vf) = match_variant_field_place(*pf)?;
-            Some((local_into, local_from, vf, pf.projection))
-        }
-        _ => None,
-    }
-}
-
-/// Match on:
-/// ```rust
-/// ((_LOCAL_FROM as Variant).FIELD: TY) = move _LOCAL_INTO;
-/// ```
-fn match_set_variant_field<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, Local, VarField<'tcx>)> {
-    match &stmt.kind {
-        StatementKind::Assign(box (place_from, Rvalue::Use(Operand::Move(place_into)))) => {
-            let local_into = place_into.as_local()?;
-            let (local_from, vf) = match_variant_field_place(*place_from)?;
-            Some((local_into, local_from, vf))
-        }
-        _ => None,
-    }
-}
-
-/// Match on:
-/// ```rust
-/// discriminant(_LOCAL_TO_SET) = VAR_IDX;
-/// ```
-fn match_set_discr<'tcx>(stmt: &Statement<'tcx>) -> Option<(Local, VariantIdx)> {
-    match &stmt.kind {
-        StatementKind::SetDiscriminant { place, variant_index } => {
-            Some((place.as_local()?, *variant_index))
-        }
-        _ => None,
-    }
-}
-
-#[derive(PartialEq, Debug)]
-struct VarField<'tcx> {
-    field: Field,
-    field_ty: Ty<'tcx>,
-    var_idx: VariantIdx,
-}
-
-/// Match on `((_LOCAL as Variant).FIELD: TY)`.
-fn match_variant_field_place<'tcx>(place: Place<'tcx>) -> Option<(Local, VarField<'tcx>)> {
-    match place.as_ref() {
-        PlaceRef {
-            local,
-            projection: &[ProjectionElem::Downcast(_, var_idx), ProjectionElem::Field(field, ty)],
-        } => Some((local, VarField { field, field_ty: ty, var_idx })),
-        _ => None,
-    }
-}
-
-/// Simplifies `SwitchInt(_) -> [targets]`,
-/// where all the `targets` have the same form,
-/// into `goto -> target_first`.
-pub struct SimplifyBranchSame;
-
-impl<'tcx> MirPass<'tcx> for SimplifyBranchSame {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        trace!("Running SimplifyBranchSame on {:?}", body.source);
-        let finder = SimplifyBranchSameOptimizationFinder { body, tcx };
-        let opts = finder.find();
-
-        let did_remove_blocks = opts.len() > 0;
-        for opt in opts.iter() {
-            trace!("SUCCESS: Applying optimization {:?}", opt);
-            // Replace `SwitchInt(..) -> [bb_first, ..];` with a `goto -> bb_first;`.
-            body.basic_blocks_mut()[opt.bb_to_opt_terminator].terminator_mut().kind =
-                TerminatorKind::Goto { target: opt.bb_to_goto };
-        }
-
-        if did_remove_blocks {
-            // We have dead blocks now, so remove those.
-            simplify::remove_dead_blocks(tcx, body);
-        }
-    }
-}
-
-#[derive(Debug)]
-struct SimplifyBranchSameOptimization {
-    /// All basic blocks are equal so go to this one
-    bb_to_goto: BasicBlock,
-    /// Basic block where the terminator can be simplified to a goto
-    bb_to_opt_terminator: BasicBlock,
-}
-
-struct SwitchTargetAndValue {
-    target: BasicBlock,
-    // None in case of the `otherwise` case
-    value: Option<u128>,
-}
-
-struct SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
-    body: &'a Body<'tcx>,
-    tcx: TyCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> {
-    fn find(&self) -> Vec<SimplifyBranchSameOptimization> {
-        self.body
-            .basic_blocks()
-            .iter_enumerated()
-            .filter_map(|(bb_idx, bb)| {
-                let (discr_switched_on, targets_and_values) = match &bb.terminator().kind {
-                    TerminatorKind::SwitchInt { targets, discr, .. } => {
-                        let targets_and_values: Vec<_> = targets.iter()
-                            .map(|(val, target)| SwitchTargetAndValue { target, value: Some(val) })
-                            .chain(once(SwitchTargetAndValue { target: targets.otherwise(), value: None }))
-                            .collect();
-                        (discr, targets_and_values)
-                    },
-                    _ => return None,
-                };
-
-                // find the adt that has its discriminant read
-                // assuming this must be the last statement of the block
-                let adt_matched_on = match &bb.statements.last()?.kind {
-                    StatementKind::Assign(box (place, rhs))
-                        if Some(*place) == discr_switched_on.place() =>
-                    {
-                        match rhs {
-                            Rvalue::Discriminant(adt_place) if adt_place.ty(self.body, self.tcx).ty.is_enum() => adt_place,
-                            _ => {
-                                trace!("NO: expected a discriminant read of an enum instead of: {:?}", rhs);
-                                return None;
-                            }
-                        }
-                    }
-                    other => {
-                        trace!("NO: expected an assignment of a discriminant read to a place. Found: {:?}", other);
-                        return None
-                    },
-                };
-
-                let mut iter_bbs_reachable = targets_and_values
-                    .iter()
-                    .map(|target_and_value| (target_and_value, &self.body.basic_blocks()[target_and_value.target]))
-                    .filter(|(_, bb)| {
-                        // Reaching `unreachable` is UB so assume it doesn't happen.
-                        bb.terminator().kind != TerminatorKind::Unreachable
-                    // But `asm!(...)` could abort the program,
-                    // so we cannot assume that the `unreachable` terminator itself is reachable.
-                    // FIXME(Centril): use a normalization pass instead of a check.
-                    || bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..)))
-                    })
-                    .peekable();
-
-                let bb_first = iter_bbs_reachable.peek().map_or(&targets_and_values[0], |(idx, _)| *idx);
-                let mut all_successors_equivalent = StatementEquality::TrivialEqual;
-
-                // All successor basic blocks must be equal or contain statements that are pairwise considered equal.
-                for ((target_and_value_l,bb_l), (target_and_value_r,bb_r)) in iter_bbs_reachable.tuple_windows() {
-                    let trivial_checks = bb_l.is_cleanup == bb_r.is_cleanup
-                                            && bb_l.terminator().kind == bb_r.terminator().kind
-                                            && bb_l.statements.len() == bb_r.statements.len();
-                    let statement_check = || {
-                        bb_l.statements.iter().zip(&bb_r.statements).try_fold(StatementEquality::TrivialEqual, |acc,(l,r)| {
-                            let stmt_equality = self.statement_equality(*adt_matched_on, &l, target_and_value_l, &r, target_and_value_r);
-                            if matches!(stmt_equality, StatementEquality::NotEqual) {
-                                // short circuit
-                                None
-                            } else {
-                                Some(acc.combine(&stmt_equality))
-                            }
-                        })
-                        .unwrap_or(StatementEquality::NotEqual)
-                    };
-                    if !trivial_checks {
-                        all_successors_equivalent = StatementEquality::NotEqual;
-                        break;
-                    }
-                    all_successors_equivalent = all_successors_equivalent.combine(&statement_check());
-                };
-
-                match all_successors_equivalent{
-                    StatementEquality::TrivialEqual => {
-                        // statements are trivially equal, so just take first
-                        trace!("Statements are trivially equal");
-                        Some(SimplifyBranchSameOptimization {
-                            bb_to_goto: bb_first.target,
-                            bb_to_opt_terminator: bb_idx,
-                        })
-                    }
-                    StatementEquality::ConsideredEqual(bb_to_choose) => {
-                        trace!("Statements are considered equal");
-                        Some(SimplifyBranchSameOptimization {
-                            bb_to_goto: bb_to_choose,
-                            bb_to_opt_terminator: bb_idx,
-                        })
-                    }
-                    StatementEquality::NotEqual => {
-                        trace!("NO: not all successors of basic block {:?} were equivalent", bb_idx);
-                        None
-                    }
-                }
-            })
-            .collect()
-    }
-
-    /// Tests if two statements can be considered equal
-    ///
-    /// Statements can be trivially equal if the kinds match.
-    /// But they can also be considered equal in the following case A:
-    /// ```
-    /// discriminant(_0) = 0;   // bb1
-    /// _0 = move _1;           // bb2
-    /// ```
-    /// In this case the two statements are equal iff
-    /// - `_0` is an enum where the variant index 0 is fieldless, and
-    /// -  bb1 was targeted by a switch where the discriminant of `_1` was switched on
-    fn statement_equality(
-        &self,
-        adt_matched_on: Place<'tcx>,
-        x: &Statement<'tcx>,
-        x_target_and_value: &SwitchTargetAndValue,
-        y: &Statement<'tcx>,
-        y_target_and_value: &SwitchTargetAndValue,
-    ) -> StatementEquality {
-        let helper = |rhs: &Rvalue<'tcx>,
-                      place: &Place<'tcx>,
-                      variant_index: &VariantIdx,
-                      side_to_choose| {
-            let place_type = place.ty(self.body, self.tcx).ty;
-            let adt = match *place_type.kind() {
-                ty::Adt(adt, _) if adt.is_enum() => adt,
-                _ => return StatementEquality::NotEqual,
-            };
-            let variant_is_fieldless = adt.variants[*variant_index].fields.is_empty();
-            if !variant_is_fieldless {
-                trace!("NO: variant {:?} was not fieldless", variant_index);
-                return StatementEquality::NotEqual;
-            }
-
-            match rhs {
-                Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => {
-                    StatementEquality::ConsideredEqual(side_to_choose)
-                }
-                _ => {
-                    trace!(
-                        "NO: RHS of assignment was {:?}, but expected it to match the adt being matched on in the switch, which is {:?}",
-                        rhs,
-                        adt_matched_on
-                    );
-                    StatementEquality::NotEqual
-                }
-            }
-        };
-        match (&x.kind, &y.kind) {
-            // trivial case
-            (x, y) if x == y => StatementEquality::TrivialEqual,
-
-            // check for case A
-            (
-                StatementKind::Assign(box (_, rhs)),
-                StatementKind::SetDiscriminant { place, variant_index },
-            )
-            // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index
-            if Some(variant_index.index() as u128) == y_target_and_value.value => {
-                // choose basic block of x, as that has the assign
-                helper(rhs, place, variant_index, x_target_and_value.target)
-            }
-            (
-                StatementKind::SetDiscriminant { place, variant_index },
-                StatementKind::Assign(box (_, rhs)),
-            )
-            // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index
-            if Some(variant_index.index() as u128) == x_target_and_value.value  => {
-                // choose basic block of y, as that has the assign
-                helper(rhs, place, variant_index, y_target_and_value.target)
-            }
-            _ => {
-                trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y);
-                StatementEquality::NotEqual
-            }
-        }
-    }
-}
-
-#[derive(Copy, Clone, Eq, PartialEq)]
-enum StatementEquality {
-    /// The two statements are trivially equal; same kind
-    TrivialEqual,
-    /// The two statements are considered equal, but may be of different kinds. The BasicBlock field is the basic block to jump to when performing the branch-same optimization.
-    /// For example, `_0 = _1` and `discriminant(_0) = discriminant(0)` are considered equal if 0 is a fieldless variant of an enum. But we don't want to jump to the basic block with the SetDiscriminant, as that is not legal if _1 is not the 0 variant index
-    ConsideredEqual(BasicBlock),
-    /// The two statements are not equal
-    NotEqual,
-}
-
-impl StatementEquality {
-    fn combine(&self, other: &StatementEquality) -> StatementEquality {
-        use StatementEquality::*;
-        match (self, other) {
-            (TrivialEqual, TrivialEqual) => TrivialEqual,
-            (TrivialEqual, ConsideredEqual(b)) | (ConsideredEqual(b), TrivialEqual) => {
-                ConsideredEqual(*b)
-            }
-            (ConsideredEqual(b1), ConsideredEqual(b2)) => {
-                if b1 == b2 {
-                    ConsideredEqual(*b1)
-                } else {
-                    NotEqual
-                }
-            }
-            (_, NotEqual) | (NotEqual, _) => NotEqual,
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
deleted file mode 100644
index 5c6c158d46e..00000000000
--- a/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-//! A pass that eliminates branches on uninhabited enum variants.
-
-use crate::transform::MirPass;
-use rustc_data_structures::stable_set::FxHashSet;
-use rustc_middle::mir::{
-    BasicBlock, BasicBlockData, Body, Local, Operand, Rvalue, StatementKind, SwitchTargets,
-    TerminatorKind,
-};
-use rustc_middle::ty::layout::TyAndLayout;
-use rustc_middle::ty::{Ty, TyCtxt};
-use rustc_target::abi::{Abi, Variants};
-
-pub struct UninhabitedEnumBranching;
-
-fn get_discriminant_local(terminator: &TerminatorKind<'_>) -> Option<Local> {
-    if let TerminatorKind::SwitchInt { discr: Operand::Move(p), .. } = terminator {
-        p.as_local()
-    } else {
-        None
-    }
-}
-
-/// If the basic block terminates by switching on a discriminant, this returns the `Ty` the
-/// discriminant is read from. Otherwise, returns None.
-fn get_switched_on_type<'tcx>(
-    block_data: &BasicBlockData<'tcx>,
-    tcx: TyCtxt<'tcx>,
-    body: &Body<'tcx>,
-) -> Option<Ty<'tcx>> {
-    let terminator = block_data.terminator();
-
-    // Only bother checking blocks which terminate by switching on a local.
-    if let Some(local) = get_discriminant_local(&terminator.kind) {
-        let stmt_before_term = (!block_data.statements.is_empty())
-            .then(|| &block_data.statements[block_data.statements.len() - 1].kind);
-
-        if let Some(StatementKind::Assign(box (l, Rvalue::Discriminant(place)))) = stmt_before_term
-        {
-            if l.as_local() == Some(local) {
-                let ty = place.ty(body, tcx).ty;
-                if ty.is_enum() {
-                    return Some(ty);
-                }
-            }
-        }
-    }
-
-    None
-}
-
-fn variant_discriminants<'tcx>(
-    layout: &TyAndLayout<'tcx>,
-    ty: Ty<'tcx>,
-    tcx: TyCtxt<'tcx>,
-) -> FxHashSet<u128> {
-    match &layout.variants {
-        Variants::Single { index } => {
-            let mut res = FxHashSet::default();
-            res.insert(index.as_u32() as u128);
-            res
-        }
-        Variants::Multiple { variants, .. } => variants
-            .iter_enumerated()
-            .filter_map(|(idx, layout)| {
-                (layout.abi != Abi::Uninhabited)
-                    .then(|| ty.discriminant_for_variant(tcx, idx).unwrap().val)
-            })
-            .collect(),
-    }
-}
-
-impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
-    fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if body.source.promoted.is_some() {
-            return;
-        }
-
-        trace!("UninhabitedEnumBranching starting for {:?}", body.source);
-
-        let basic_block_count = body.basic_blocks().len();
-
-        for bb in 0..basic_block_count {
-            let bb = BasicBlock::from_usize(bb);
-            trace!("processing block {:?}", bb);
-
-            let discriminant_ty =
-                if let Some(ty) = get_switched_on_type(&body.basic_blocks()[bb], tcx, body) {
-                    ty
-                } else {
-                    continue;
-                };
-
-            let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
-
-            let allowed_variants = if let Ok(layout) = layout {
-                variant_discriminants(&layout, discriminant_ty, tcx)
-            } else {
-                continue;
-            };
-
-            trace!("allowed_variants = {:?}", allowed_variants);
-
-            if let TerminatorKind::SwitchInt { targets, .. } =
-                &mut body.basic_blocks_mut()[bb].terminator_mut().kind
-            {
-                let new_targets = SwitchTargets::new(
-                    targets.iter().filter(|(val, _)| allowed_variants.contains(val)),
-                    targets.otherwise(),
-                );
-
-                *targets = new_targets;
-            } else {
-                unreachable!()
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs
deleted file mode 100644
index e7fb6b4f6b4..00000000000
--- a/compiler/rustc_mir/src/transform/unreachable_prop.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-//! A pass that propagates the unreachable terminator of a block to its predecessors
-//! when all of their successors are unreachable. This is achieved through a
-//! post-order traversal of the blocks.
-
-use crate::transform::simplify;
-use crate::transform::MirPass;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_middle::mir::*;
-use rustc_middle::ty::TyCtxt;
-
-pub struct UnreachablePropagation;
-
-impl MirPass<'_> for UnreachablePropagation {
-    fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-        if tcx.sess.mir_opt_level() < 4 {
-            // Enable only under -Zmir-opt-level=4 as in some cases (check the deeply-nested-opt
-            // perf benchmark) LLVM may spend quite a lot of time optimizing the generated code.
-            return;
-        }
-
-        let mut unreachable_blocks = FxHashSet::default();
-        let mut replacements = FxHashMap::default();
-
-        for (bb, bb_data) in traversal::postorder(body) {
-            let terminator = bb_data.terminator();
-            // HACK: If the block contains any asm statement it is not regarded as unreachable.
-            // This is a temporary solution that handles possibly diverging asm statements.
-            // Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
-            let asm_stmt_in_block = || {
-                bb_data.statements.iter().any(|stmt: &Statement<'_>| match stmt.kind {
-                    StatementKind::LlvmInlineAsm(..) => true,
-                    _ => false,
-                })
-            };
-
-            if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
-                unreachable_blocks.insert(bb);
-            } else {
-                let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
-                let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
-
-                if let Some(terminator_kind) = terminator_kind_opt {
-                    if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
-                        unreachable_blocks.insert(bb);
-                    }
-                    replacements.insert(bb, terminator_kind);
-                }
-            }
-        }
-
-        let replaced = !replacements.is_empty();
-        for (bb, terminator_kind) in replacements {
-            if !tcx.consider_optimizing(|| {
-                format!("UnreachablePropagation {:?} ", body.source.def_id())
-            }) {
-                break;
-            }
-
-            body.basic_blocks_mut()[bb].terminator_mut().kind = terminator_kind;
-        }
-
-        if replaced {
-            simplify::remove_dead_blocks(tcx, body);
-        }
-    }
-}
-
-fn remove_successors<F>(
-    terminator_kind: &TerminatorKind<'tcx>,
-    predicate: F,
-) -> Option<TerminatorKind<'tcx>>
-where
-    F: Fn(BasicBlock) -> bool,
-{
-    let terminator = match *terminator_kind {
-        TerminatorKind::Goto { target } if predicate(target) => TerminatorKind::Unreachable,
-        TerminatorKind::SwitchInt { ref discr, switch_ty, ref targets } => {
-            let otherwise = targets.otherwise();
-
-            let original_targets_len = targets.iter().len() + 1;
-            let (mut values, mut targets): (Vec<_>, Vec<_>) =
-                targets.iter().filter(|(_, bb)| !predicate(*bb)).unzip();
-
-            if !predicate(otherwise) {
-                targets.push(otherwise);
-            } else {
-                values.pop();
-            }
-
-            let retained_targets_len = targets.len();
-
-            if targets.is_empty() {
-                TerminatorKind::Unreachable
-            } else if targets.len() == 1 {
-                TerminatorKind::Goto { target: targets[0] }
-            } else if original_targets_len != retained_targets_len {
-                TerminatorKind::SwitchInt {
-                    discr: discr.clone(),
-                    switch_ty,
-                    targets: SwitchTargets::new(
-                        values.iter().copied().zip(targets.iter().copied()),
-                        *targets.last().unwrap(),
-                    ),
-                }
-            } else {
-                return None;
-            }
-        }
-        _ => return None,
-    };
-    Some(terminator)
-}
diff --git a/compiler/rustc_mir/src/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs
index 8f9db6daba7..741c1e6b2c6 100644
--- a/compiler/rustc_mir/src/util/mod.rs
+++ b/compiler/rustc_mir/src/util/mod.rs
@@ -7,10 +7,10 @@ mod alignment;
 pub mod collect_writes;
 mod find_self_call;
 mod generic_graph;
-pub(crate) mod generic_graphviz;
+pub mod generic_graphviz;
 mod graphviz;
 pub mod pretty;
-pub(crate) mod spanview;
+pub mod spanview;
 
 pub use self::aggregate::expand_aggregate;
 pub use self::alignment::is_disaligned;
diff --git a/compiler/rustc_mir/src/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs
index ec1aa5b476b..db98cb76343 100644
--- a/compiler/rustc_mir/src/util/pretty.rs
+++ b/compiler/rustc_mir/src/util/pretty.rs
@@ -7,7 +7,6 @@ use std::path::{Path, PathBuf};
 
 use super::graphviz::write_mir_fn_graphviz;
 use super::spanview::write_mir_fn_spanview;
-use crate::transform::MirSource;
 use either::Either;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::DefId;
@@ -16,6 +15,7 @@ use rustc_middle::mir::interpret::{
     read_target_uint, AllocId, Allocation, ConstValue, GlobalAlloc, Pointer, Provenance,
 };
 use rustc_middle::mir::visit::Visitor;
+use rustc_middle::mir::MirSource;
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt, TyS, TypeFoldable, TypeVisitor};
 use rustc_target::abi::Size;