From 9d999bb035234f2d3eeff38853e262728f9031c6 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 1/9] Do not use `for_each_assignment_mut` to iterate over
 assignment statements

`for_each_assignment_mut` can skip assignment statements with side effects,
which can result in some assignment statements retrieving outdated value.
For example, it may skip a dereference assignment statement.
---
 compiler/rustc_mir_transform/src/gvn.rs       | 77 +++++++++----------
 compiler/rustc_mir_transform/src/ssa.rs       | 38 ---------
 ..._simplification.hello.GVN.panic-abort.diff |  3 +-
 ...simplification.hello.GVN.panic-unwind.diff |  3 +-
 4 files changed, 41 insertions(+), 80 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 0a54c780f31..2abb4e8b8ce 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -3,14 +3,16 @@
 //! MIR may contain repeated and/or redundant computations. The objective of this pass is to detect
 //! such redundancies and re-use the already-computed result when possible.
 //!
-//! In a first pass, we compute a symbolic representation of values that are assigned to SSA
-//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
-//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
-//!
 //! From those assignments, we construct a mapping `VnIndex -> Vec<(Local, Location)>` of available
 //! values, the locals in which they are stored, and the assignment location.
 //!
-//! In a second pass, we traverse all (non SSA) assignments `x = rvalue` and operands. For each
+//! We traverse all assignments `x = rvalue` and operands.
+//!
+//! For each SSA one, we compute a symbolic representation of values that are assigned to SSA
+//! locals. This symbolic representation is defined by the `Value` enum. Each produced instance of
+//! `Value` is interned as a `VnIndex`, which allows us to cheaply compute identical values.
+//!
+//! For each non-SSA
 //! one, we compute the `VnIndex` of the rvalue. If this `VnIndex` is associated to a constant, we
 //! replace the rvalue/operand by that constant. Otherwise, if there is an SSA local `y`
 //! associated to this `VnIndex`, and if its definition location strictly dominates the assignment
@@ -107,7 +109,7 @@ use rustc_span::def_id::DefId;
 use smallvec::SmallVec;
 use tracing::{debug, instrument, trace};
 
-use crate::ssa::{AssignedValue, SsaLocals};
+use crate::ssa::SsaLocals;
 
 pub(super) struct GVN;
 
@@ -126,31 +128,11 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
         let dominators = body.basic_blocks.dominators().clone();
 
         let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
-        ssa.for_each_assignment_mut(
-            body.basic_blocks.as_mut_preserves_cfg(),
-            |local, value, location| {
-                let value = match value {
-                    // We do not know anything of this assigned value.
-                    AssignedValue::Arg | AssignedValue::Terminator => None,
-                    // Try to get some insight.
-                    AssignedValue::Rvalue(rvalue) => {
-                        let value = state.simplify_rvalue(rvalue, location);
-                        // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
-                        // `local` as reusable if we have an exact type match.
-                        if state.local_decls[local].ty != rvalue.ty(state.local_decls, tcx) {
-                            return;
-                        }
-                        value
-                    }
-                };
-                // `next_opaque` is `Some`, so `new_opaque` must return `Some`.
-                let value = value.or_else(|| state.new_opaque()).unwrap();
-                state.assign(local, value);
-            },
-        );
 
-        // Stop creating opaques during replacement as it is useless.
-        state.next_opaque = None;
+        for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) {
+            let opaque = state.new_opaque().unwrap();
+            state.assign(local, opaque);
+        }
 
         let reverse_postorder = body.basic_blocks.reverse_postorder().to_vec();
         for bb in reverse_postorder {
@@ -250,7 +232,6 @@ struct VnState<'body, 'tcx> {
     locals: IndexVec<Local, Option<VnIndex>>,
     /// Locals that are assigned that value.
     // This vector does not hold all the values of `VnIndex` that we create.
-    // It stops at the largest value created in the first phase of collecting assignments.
     rev_locals: IndexVec<VnIndex, SmallVec<[Local; 1]>>,
     values: FxIndexSet<Value<'tcx>>,
     /// Values evaluated as constants if possible.
@@ -345,6 +326,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     /// Record that `local` is assigned `value`. `local` must be SSA.
     #[instrument(level = "trace", skip(self))]
     fn assign(&mut self, local: Local, value: VnIndex) {
+        debug_assert!(self.ssa.is_ssa(local));
         self.locals[local] = Some(value);
 
         // Only register the value if its type is `Sized`, as we will emit copies of it.
@@ -1751,15 +1733,19 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
         if let StatementKind::Assign(box (ref mut lhs, ref mut rvalue)) = stmt.kind {
             self.simplify_place_projection(lhs, location);
 
-            // Do not try to simplify a constant, it's already in canonical shape.
-            if matches!(rvalue, Rvalue::Use(Operand::Constant(_))) {
-                return;
-            }
-
-            let value = lhs
-                .as_local()
-                .and_then(|local| self.locals[local])
-                .or_else(|| self.simplify_rvalue(rvalue, location));
+            let value = self.simplify_rvalue(rvalue, location);
+            let value = if let Some(local) = lhs.as_local()
+                && self.ssa.is_ssa(local)
+                // FIXME(#112651) `rvalue` may have a subtype to `local`. We can only mark
+                // `local` as reusable if we have an exact type match.
+                && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx)
+            {
+                let value = value.or_else(|| self.new_opaque()).unwrap();
+                self.assign(local, value);
+                Some(value)
+            } else {
+                value
+            };
             let Some(value) = value else { return };
 
             if let Some(const_) = self.try_as_constant(value) {
@@ -1775,6 +1761,17 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
         }
         self.super_statement(stmt, location);
     }
+
+    fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
+        if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator
+            && let Some(local) = destination.as_local()
+            && self.ssa.is_ssa(local)
+        {
+            let opaque = self.new_opaque().unwrap();
+            self.assign(local, opaque);
+        }
+        self.super_terminator(terminator, location);
+    }
 }
 
 struct StorageRemover<'tcx> {
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index 3d512fb064e..edd0cabca49 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -32,12 +32,6 @@ pub(super) struct SsaLocals {
     borrowed_locals: DenseBitSet<Local>,
 }
 
-pub(super) enum AssignedValue<'a, 'tcx> {
-    Arg,
-    Rvalue(&'a mut Rvalue<'tcx>),
-    Terminator,
-}
-
 impl SsaLocals {
     pub(super) fn new<'tcx>(
         tcx: TyCtxt<'tcx>,
@@ -152,38 +146,6 @@ impl SsaLocals {
         })
     }
 
-    pub(super) fn for_each_assignment_mut<'tcx>(
-        &self,
-        basic_blocks: &mut IndexSlice<BasicBlock, BasicBlockData<'tcx>>,
-        mut f: impl FnMut(Local, AssignedValue<'_, 'tcx>, Location),
-    ) {
-        for &local in &self.assignment_order {
-            match self.assignments[local] {
-                Set1::One(DefLocation::Argument) => f(
-                    local,
-                    AssignedValue::Arg,
-                    Location { block: START_BLOCK, statement_index: 0 },
-                ),
-                Set1::One(DefLocation::Assignment(loc)) => {
-                    let bb = &mut basic_blocks[loc.block];
-                    // `loc` must point to a direct assignment to `local`.
-                    let stmt = &mut bb.statements[loc.statement_index];
-                    let StatementKind::Assign(box (target, ref mut rvalue)) = stmt.kind else {
-                        bug!()
-                    };
-                    assert_eq!(target.as_local(), Some(local));
-                    f(local, AssignedValue::Rvalue(rvalue), loc)
-                }
-                Set1::One(DefLocation::CallReturn { call, .. }) => {
-                    let bb = &mut basic_blocks[call];
-                    let loc = Location { block: call, statement_index: bb.statements.len() };
-                    f(local, AssignedValue::Terminator, loc)
-                }
-                _ => {}
-            }
-        }
-    }
-
     /// Compute the equivalence classes for locals, based on copy statements.
     ///
     /// The returned vector maps each local to the one it copies. In the following case:
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
index 886f9a68dd9..417406de39b 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-abort.diff
@@ -8,8 +8,9 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = const <bool as NeedsDrop>::NEEDS;
+-         _1 = const <bool as NeedsDrop>::NEEDS;
 -         switchInt(move _1) -> [0: bb2, otherwise: bb1];
++         _1 = const false;
 +         switchInt(const false) -> [0: bb2, otherwise: bb1];
       }
   
diff --git a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
index cc53b213397..63ba2c6865f 100644
--- a/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/control_flow_simplification.hello.GVN.panic-unwind.diff
@@ -8,8 +8,9 @@
   
       bb0: {
           StorageLive(_1);
-          _1 = const <bool as NeedsDrop>::NEEDS;
+-         _1 = const <bool as NeedsDrop>::NEEDS;
 -         switchInt(move _1) -> [0: bb2, otherwise: bb1];
++         _1 = const false;
 +         switchInt(const false) -> [0: bb2, otherwise: bb1];
       }
   

From 84af55679131e5074b7236fbdd98b12e9012b94e Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 2/9] `next_opaque` is no longer an `Option`

---
 compiler/rustc_mir_transform/src/gvn.rs | 69 ++++++++++++-------------
 1 file changed, 32 insertions(+), 37 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 2abb4e8b8ce..42d736cf5f4 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -130,7 +130,7 @@ impl<'tcx> crate::MirPass<'tcx> for GVN {
         let mut state = VnState::new(tcx, body, typing_env, &ssa, dominators, &body.local_decls);
 
         for local in body.args_iter().filter(|&local| ssa.is_ssa(local)) {
-            let opaque = state.new_opaque().unwrap();
+            let opaque = state.new_opaque();
             state.assign(local, opaque);
         }
 
@@ -237,8 +237,7 @@ struct VnState<'body, 'tcx> {
     /// Values evaluated as constants if possible.
     evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
     /// Counter to generate different values.
-    /// This is an option to stop creating opaques during replacement.
-    next_opaque: Option<usize>,
+    next_opaque: usize,
     /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
     feature_unsized_locals: bool,
     ssa: &'body SsaLocals,
@@ -270,7 +269,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             rev_locals: IndexVec::with_capacity(num_values),
             values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
             evaluated: IndexVec::with_capacity(num_values),
-            next_opaque: Some(1),
+            next_opaque: 1,
             feature_unsized_locals: tcx.features().unsized_locals(),
             ssa,
             dominators,
@@ -291,32 +290,31 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             let evaluated = self.eval_to_const(index);
             let _index = self.evaluated.push(evaluated);
             debug_assert_eq!(index, _index);
-            // No need to push to `rev_locals` if we finished listing assignments.
-            if self.next_opaque.is_some() {
-                let _index = self.rev_locals.push(SmallVec::new());
-                debug_assert_eq!(index, _index);
-            }
+            let _index = self.rev_locals.push(SmallVec::new());
+            debug_assert_eq!(index, _index);
         }
         index
     }
 
+    fn next_opaque(&mut self) -> usize {
+        let next_opaque = self.next_opaque;
+        self.next_opaque += 1;
+        next_opaque
+    }
+
     /// Create a new `Value` for which we have no information at all, except that it is distinct
     /// from all the others.
     #[instrument(level = "trace", skip(self), ret)]
-    fn new_opaque(&mut self) -> Option<VnIndex> {
-        let next_opaque = self.next_opaque.as_mut()?;
-        let value = Value::Opaque(*next_opaque);
-        *next_opaque += 1;
-        Some(self.insert(value))
+    fn new_opaque(&mut self) -> VnIndex {
+        let value = Value::Opaque(self.next_opaque());
+        self.insert(value)
     }
 
     /// Create a new `Value::Address` distinct from all the others.
     #[instrument(level = "trace", skip(self), ret)]
-    fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> Option<VnIndex> {
-        let next_opaque = self.next_opaque.as_mut()?;
-        let value = Value::Address { place, kind, provenance: *next_opaque };
-        *next_opaque += 1;
-        Some(self.insert(value))
+    fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> VnIndex {
+        let value = Value::Address { place, kind, provenance: self.next_opaque() };
+        self.insert(value)
     }
 
     fn get(&self, index: VnIndex) -> &Value<'tcx> {
@@ -337,21 +335,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         }
     }
 
-    fn insert_constant(&mut self, value: Const<'tcx>) -> Option<VnIndex> {
+    fn insert_constant(&mut self, value: Const<'tcx>) -> VnIndex {
         let disambiguator = if value.is_deterministic() {
             // The constant is deterministic, no need to disambiguate.
             0
         } else {
             // Multiple mentions of this constant will yield different values,
             // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`.
-            let next_opaque = self.next_opaque.as_mut()?;
-            let disambiguator = *next_opaque;
-            *next_opaque += 1;
+            let disambiguator = self.next_opaque();
             // `disambiguator: 0` means deterministic.
             debug_assert_ne!(disambiguator, 0);
             disambiguator
         };
-        Some(self.insert(Value::Constant { value, disambiguator }))
+        self.insert(Value::Constant { value, disambiguator })
     }
 
     fn insert_bool(&mut self, flag: bool) -> VnIndex {
@@ -812,7 +808,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         location: Location,
     ) -> Option<VnIndex> {
         match *operand {
-            Operand::Constant(ref constant) => self.insert_constant(constant.const_),
+            Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)),
             Operand::Copy(ref mut place) | Operand::Move(ref mut place) => {
                 let value = self.simplify_place_value(place, location)?;
                 if let Some(const_) = self.try_as_constant(value) {
@@ -848,11 +844,11 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             Rvalue::Aggregate(..) => return self.simplify_aggregate(rvalue, location),
             Rvalue::Ref(_, borrow_kind, ref mut place) => {
                 self.simplify_place_projection(place, location);
-                return self.new_pointer(*place, AddressKind::Ref(borrow_kind));
+                return Some(self.new_pointer(*place, AddressKind::Ref(borrow_kind)));
             }
             Rvalue::RawPtr(mutbl, ref mut place) => {
                 self.simplify_place_projection(place, location);
-                return self.new_pointer(*place, AddressKind::Address(mutbl));
+                return Some(self.new_pointer(*place, AddressKind::Address(mutbl)));
             }
             Rvalue::WrapUnsafeBinder(ref mut op, ty) => {
                 let value = self.simplify_operand(op, location)?;
@@ -1016,7 +1012,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
 
             if is_zst {
                 let ty = rvalue.ty(self.local_decls, tcx);
-                return self.insert_constant(Const::zero_sized(ty));
+                return Some(self.insert_constant(Const::zero_sized(ty)));
             }
         }
 
@@ -1045,11 +1041,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         };
 
-        let fields: Option<Vec<_>> = field_ops
+        let mut fields: Vec<_> = field_ops
             .iter_mut()
-            .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
+            .map(|op| self.simplify_operand(op, location).unwrap_or_else(|| self.new_opaque()))
             .collect();
-        let mut fields = fields?;
 
         if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
             let mut was_updated = false;
@@ -1177,7 +1172,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             ) if let ty::Slice(..) = to.builtin_deref(true).unwrap().kind()
                 && let ty::Array(_, len) = from.builtin_deref(true).unwrap().kind() =>
             {
-                return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
+                return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
             }
             _ => Value::UnaryOp(op, arg_index),
         };
@@ -1373,7 +1368,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         if let CastKind::PointerCoercion(ReifyFnPointer | ClosureFnPointer(_), _) = kind {
             // Each reification of a generic fn may get a different pointer.
             // Do not try to merge them.
-            return self.new_opaque();
+            return Some(self.new_opaque());
         }
 
         let mut was_ever_updated = false;
@@ -1489,7 +1484,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         // Trivial case: we are fetching a statically known length.
         let place_ty = place.ty(self.local_decls, self.tcx).ty;
         if let ty::Array(_, len) = place_ty.kind() {
-            return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
+            return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
         }
 
         let mut inner = self.simplify_place_value(place, location)?;
@@ -1511,7 +1506,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             && let Some(to) = to.builtin_deref(true)
             && let ty::Slice(..) = to.kind()
         {
-            return self.insert_constant(Const::Ty(self.tcx.types.usize, *len));
+            return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len)));
         }
 
         // Fallback: a symbolic `Len`.
@@ -1740,7 +1735,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
                 // `local` as reusable if we have an exact type match.
                 && self.local_decls[local].ty == rvalue.ty(self.local_decls, self.tcx)
             {
-                let value = value.or_else(|| self.new_opaque()).unwrap();
+                let value = value.unwrap_or_else(|| self.new_opaque());
                 self.assign(local, value);
                 Some(value)
             } else {
@@ -1767,7 +1762,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
             && let Some(local) = destination.as_local()
             && self.ssa.is_ssa(local)
         {
-            let opaque = self.new_opaque().unwrap();
+            let opaque = self.new_opaque();
             self.assign(local, opaque);
         }
         self.super_terminator(terminator, location);

From 7830406df1232c59f82d870c218901b8643701bb Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 3/9] Invalidate all dereferences for non-local assignments

---
 compiler/rustc_data_structures/src/fx.rs      |  2 +
 compiler/rustc_mir_transform/src/gvn.rs       | 38 +++++++++++++++----
 ..._aggregate_to_copy_miscompile.foo.GVN.diff |  8 ++--
 3 files changed, 35 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_data_structures/src/fx.rs b/compiler/rustc_data_structures/src/fx.rs
index 80e72250470..f0db9623b67 100644
--- a/compiler/rustc_data_structures/src/fx.rs
+++ b/compiler/rustc_data_structures/src/fx.rs
@@ -9,6 +9,8 @@ pub type FxIndexSet<V> = indexmap::IndexSet<V, BuildHasherDefault<FxHasher>>;
 pub type IndexEntry<'a, K, V> = indexmap::map::Entry<'a, K, V>;
 pub type IndexOccupiedEntry<'a, K, V> = indexmap::map::OccupiedEntry<'a, K, V>;
 
+pub use indexmap::set::MutableValues;
+
 #[macro_export]
 macro_rules! define_id_collections {
     ($map_name:ident, $set_name:ident, $entry_name:ident, $key:ty) => {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 42d736cf5f4..944c21eab40 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -93,7 +93,7 @@ use rustc_const_eval::interpret::{
     ImmTy, Immediate, InterpCx, MemPlaceMeta, MemoryKind, OpTy, Projectable, Scalar,
     intern_const_alloc_for_constprop,
 };
-use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::fx::{FxIndexSet, MutableValues};
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::DenseBitSet;
@@ -238,6 +238,8 @@ struct VnState<'body, 'tcx> {
     evaluated: IndexVec<VnIndex, Option<OpTy<'tcx>>>,
     /// Counter to generate different values.
     next_opaque: usize,
+    /// Cache the deref values.
+    derefs: Vec<VnIndex>,
     /// Cache the value of the `unsized_locals` features, to avoid fetching it repeatedly in a loop.
     feature_unsized_locals: bool,
     ssa: &'body SsaLocals,
@@ -270,6 +272,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             values: FxIndexSet::with_capacity_and_hasher(num_values, Default::default()),
             evaluated: IndexVec::with_capacity(num_values),
             next_opaque: 1,
+            derefs: Vec::new(),
             feature_unsized_locals: tcx.features().unsized_locals(),
             ssa,
             dominators,
@@ -368,6 +371,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         self.insert(Value::Aggregate(AggregateTy::Tuple, VariantIdx::ZERO, values))
     }
 
+    fn insert_deref(&mut self, value: VnIndex) -> VnIndex {
+        let value = self.insert(Value::Projection(value, ProjectionElem::Deref));
+        self.derefs.push(value);
+        value
+    }
+
+    fn invalidate_derefs(&mut self) {
+        for deref in std::mem::take(&mut self.derefs) {
+            let opaque = self.next_opaque();
+            *self.values.get_index_mut2(deref.index()).unwrap() = Value::Opaque(opaque);
+        }
+    }
+
     #[instrument(level = "trace", skip(self), ret)]
     fn eval_to_const(&mut self, value: VnIndex) -> Option<OpTy<'tcx>> {
         use Value::*;
@@ -634,7 +650,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 {
                     // An immutable borrow `_x` always points to the same value for the
                     // lifetime of the borrow, so we can merge all instances of `*_x`.
-                    ProjectionElem::Deref
+                    return Some(self.insert_deref(value));
                 } else {
                     return None;
                 }
@@ -1739,6 +1755,8 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
                 self.assign(local, value);
                 Some(value)
             } else {
+                // Non-local assignments maybe invalidate deref.
+                self.invalidate_derefs();
                 value
             };
             let Some(value) = value else { return };
@@ -1758,12 +1776,16 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
     }
 
     fn visit_terminator(&mut self, terminator: &mut Terminator<'tcx>, location: Location) {
-        if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator
-            && let Some(local) = destination.as_local()
-            && self.ssa.is_ssa(local)
-        {
-            let opaque = self.new_opaque();
-            self.assign(local, opaque);
+        if let Terminator { kind: TerminatorKind::Call { destination, .. }, .. } = terminator {
+            if let Some(local) = destination.as_local()
+                && self.ssa.is_ssa(local)
+            {
+                let opaque = self.new_opaque();
+                self.assign(local, opaque);
+            }
+            // Function calls maybe invalidate nested deref, and non-local assignments maybe invalidate deref.
+            // Currently, no distinction is made between these two cases.
+            self.invalidate_derefs();
         }
         self.super_terminator(terminator, location);
     }
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
index 22d4277ee45..2efc4ef5604 100644
--- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
@@ -19,8 +19,7 @@
       }
   
       bb0: {
--         StorageLive(_2);
-+         nop;
+          StorageLive(_2);
           StorageLive(_3);
           StorageLive(_4);
           _4 = &_1;
@@ -50,13 +49,12 @@
           StorageLive(_9);
           _9 = copy _6;
 -         _0 = Option::<i32>::Some(move _9);
-+         _0 = copy (*_2);
++         _0 = Option::<i32>::Some(copy _6);
           StorageDead(_9);
 -         StorageDead(_6);
 +         nop;
           StorageDead(_4);
--         StorageDead(_2);
-+         nop;
+          StorageDead(_2);
           return;
       }
   

From 7e0463fe93b7fec40e564fb1312296ed608ce837 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 4/9] Revert "comment out the old tests instead of adjusting
 them"

This reverts commit 906f66fb4c22daa8a6f97e5c048e9f6ab3fd9051.
---
 tests/coverage/closure.cov-map                | 18 +++++------
 .../const_prop/read_immutable_static.rs       |  3 +-
 tests/mir-opt/const_prop/ref_deref_project.rs |  3 +-
 tests/mir-opt/const_prop/slice_len.rs         |  5 ++-
 .../gvn.fn_pointers.GVN.panic-abort.diff      | 18 +++++------
 .../gvn.fn_pointers.GVN.panic-unwind.diff     | 18 +++++------
 tests/mir-opt/gvn.rs                          | 31 +++++++++++--------
 .../pre-codegen/deref_nested_borrows.rs       |  1 -
 8 files changed, 48 insertions(+), 49 deletions(-)

diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
index 2d784ba09b6..640f9895684 100644
--- a/tests/coverage/closure.cov-map
+++ b/tests/coverage/closure.cov-map
@@ -140,19 +140,17 @@ Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 Highest counter ID seen: c1
 
-Function name: closure::main::{closure#18}
-Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e]
+Function name: closure::main::{closure#18} (unused)
+Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 0
 Number of file 0 mappings: 4
-- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28)
-- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
-- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18)
-    = (c0 - c1)
-- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14)
-Highest counter ID seen: c1
+- Code(Zero) at (prev + 25, 13) to (start + 2, 28)
+- Code(Zero) at (prev + 2, 29) to (start + 2, 18)
+- Code(Zero) at (prev + 2, 17) to (start + 0, 18)
+- Code(Zero) at (prev + 1, 17) to (start + 1, 14)
+Highest counter ID seen: (none)
 
 Function name: closure::main::{closure#19}
 Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e]
diff --git a/tests/mir-opt/const_prop/read_immutable_static.rs b/tests/mir-opt/const_prop/read_immutable_static.rs
index 98ba76fb765..f88e4b3de93 100644
--- a/tests/mir-opt/const_prop/read_immutable_static.rs
+++ b/tests/mir-opt/const_prop/read_immutable_static.rs
@@ -6,7 +6,6 @@ static FOO: u8 = 2;
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
-    // Disabled due to <https://github.com/rust-lang/rust/issues/130853>
-    // COM: CHECK: [[x]] = const 4_u8;
+    // CHECK-NOT: [[x]] = const 4_u8;
     let x = FOO + FOO;
 }
diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs
index 31108e1a57f..813b4ae4745 100644
--- a/tests/mir-opt/const_prop/ref_deref_project.rs
+++ b/tests/mir-opt/const_prop/ref_deref_project.rs
@@ -5,7 +5,6 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // Disabled due to <https://github.com/rust-lang/rust/issues/130853>
-    // COM: CHECK: [[a]] = const 5_i32;
+    // CHECK-NOT: [[a]] = const 5_i32;
     let a = *(&(4, 5).1);
 }
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index 498e09fbb65..eb86e28408a 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -8,8 +8,7 @@ fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
     // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast));
-    // Disabled due to <https://github.com/rust-lang/rust/issues/130853>
-    // COM: CHECK: assert(const true,
-    // COM: CHECK: [[a]] = const 2_u32;
+    // CHECK-NOT: assert(const true,
+    // CHECK-NOT: [[a]] = const 2_u32;
     let a = (&[1u32, 2, 3] as &[u32])[1];
 }
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 7f99b83d937..3cce35d34e9 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
+      let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
+      let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
+              let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
+-         _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
 +         nop;
           StorageLive(_9);
 -         _9 = copy _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = copy _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index 06dd0502f30..d85aca040fe 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -8,10 +8,10 @@
       let mut _3: fn(u8) -> u8;
       let _5: ();
       let mut _6: fn(u8) -> u8;
-      let mut _9: {closure@$DIR/gvn.rs:615:19: 615:21};
+      let mut _9: {closure@$DIR/gvn.rs:620:19: 620:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:615:19: 615:21};
+      let mut _13: {closure@$DIR/gvn.rs:620:19: 620:21};
       let _14: ();
       let mut _15: fn();
       scope 1 {
@@ -19,7 +19,7 @@
           let _4: fn(u8) -> u8;
           scope 2 {
               debug g => _4;
-              let _7: {closure@$DIR/gvn.rs:615:19: 615:21};
+              let _7: {closure@$DIR/gvn.rs:620:19: 620:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:615:19: 615:21};
+-         _7 = {closure@$DIR/gvn.rs:620:19: 620:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
 +         nop;
           StorageLive(_9);
 -         _9 = copy _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = copy _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:615:19: 615:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:620:19: 620:21} as fn() (PointerCoercion(ClosureFnPointer(Safe), AsCast));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index c895a579259..be97470ebb1 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -100,17 +100,18 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
     opaque((x * y) - y);
 
     // We cannot substitute through an immutable reference.
-    // (Disabled due to <https://github.com/rust-lang/rust/issues/130853>)
     // CHECK: [[ref:_.*]] = &_3;
     // CHECK: [[deref:_.*]] = copy (*[[ref]]);
-    // COM: CHECK: [[addref:_.*]] = Add(copy [[deref]], copy _1);
-    // COM: CHECK: opaque::<u64>(copy [[addref]])
-    // COM: CHECK: opaque::<u64>(copy [[addref]])
+    // CHECK: [[addref:_.*]] = Add(move [[deref]], copy _1);
+    // CHECK: opaque::<u64>(move [[addref]])
+    // CHECK: [[deref2:_.*]] = copy (*[[ref]]);
+    // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
+    // CHECK: opaque::<u64>(move [[addref2]])
     let a = &z;
     opaque(*a + x);
     opaque(*a + x);
 
-    // And certainly not through a mutable reference or a pointer.
+    // But not through a mutable reference or a pointer.
     // CHECK: [[mut:_.*]] = &mut _3;
     // CHECK: [[addmut:_.*]] = Add(
     // CHECK: opaque::<u64>(move [[addmut]])
@@ -142,9 +143,11 @@ fn subexpression_elimination(x: u64, y: u64, mut z: u64) {
     // Important: `e` is not `a`!
     // CHECK: [[ref2:_.*]] = &_3;
     // CHECK: [[deref2:_.*]] = copy (*[[ref2]]);
-    // COM: CHECK: [[addref2:_.*]] = Add(copy [[deref2]], copy _1);
-    // COM: CHECK: opaque::<u64>(copy [[addref2]])
-    // COM: CHECK: opaque::<u64>(copy [[addref2]])
+    // CHECK: [[addref2:_.*]] = Add(move [[deref2]], copy _1);
+    // CHECK: opaque::<u64>(move [[addref2]])
+    // CHECK: [[deref3:_.*]] = copy (*[[ref2]]);
+    // CHECK: [[addref3:_.*]] = Add(move [[deref3]], copy _1);
+    // CHECK: opaque::<u64>(move [[addref3]])
     let e = &z;
     opaque(*e + x);
     opaque(*e + x);
@@ -499,8 +502,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
     // Do not reuse dereferences of `&Freeze`.
     // CHECK: [[ref:_.*]] = &(*_1);
     // CHECK: [[st7:_.*]] = copy (*[[ref]]);
-    // COM: CHECK: opaque::<u32>(copy [[st7]])
-    // COM: CHECK: opaque::<u32>(copy [[st7]])
+    // CHECK: opaque::<u32>(move [[st7]])
+    // CHECK: [[st8:_.*]] = copy (*[[ref]]);
+    // CHECK: opaque::<u32>(move [[st8]])
     let z = &*t;
     opaque(*z);
     opaque(*z);
@@ -519,8 +523,9 @@ fn dereferences(t: &mut u32, u: &impl Copy, s: &S<u32>) {
 
     // `*s` is not Copy, but `(*s).0` is, but we still cannot reuse.
     // CHECK: [[st10:_.*]] = copy ((*_3).0: u32);
-    // COM: CHECK: opaque::<u32>(copy [[st10]])
-    // COM: CHECK: opaque::<u32>(copy [[st10]])
+    // CHECK: opaque::<u32>(move [[st10]])
+    // CHECK: [[st11:_.*]] = copy ((*_3).0: u32);
+    // CHECK: opaque::<u32>(move [[st11]])
     opaque(s.0);
     opaque(s.0);
 }
@@ -737,7 +742,7 @@ fn borrowed<T: Copy + Freeze>(x: T) {
     // CHECK: bb1: {
     // CHECK-NEXT: _0 = opaque::<T>(copy _1)
     // CHECK: bb2: {
-    // COM: CHECK-NEXT: _0 = opaque::<T>(copy _1)
+    // CHECK-NEXT: _0 = opaque::<T>(copy (*_3))
     mir! {
         {
             let a = x;
diff --git a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs
index 4f70ec36bc9..738cd981ae6 100644
--- a/tests/mir-opt/pre-codegen/deref_nested_borrows.rs
+++ b/tests/mir-opt/pre-codegen/deref_nested_borrows.rs
@@ -1,4 +1,3 @@
-//! Regression test for <https://github.com/rust-lang/rust/issues/130853>
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 
 fn src(x: &&u8) -> bool {

From fefb0dba824d7a98bbceba63e434279ff7377a45 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 5/9] Partially revert "Do not unify dereferences in GVN."

This reverts commit 917dd826286bd85e26310e4db4a125d4038c277e.
---
 compiler/rustc_mir_transform/src/gvn.rs | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 944c21eab40..a93fdff5817 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -642,9 +642,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         let proj = match proj {
             ProjectionElem::Deref => {
                 let ty = place.ty(self.local_decls, self.tcx).ty;
-                // unsound: https://github.com/rust-lang/rust/issues/130853
-                if self.tcx.sess.opts.unstable_opts.unsound_mir_opts
-                    && let Some(Mutability::Not) = ty.ref_mutability()
+                if let Some(Mutability::Not) = ty.ref_mutability()
                     && let Some(pointee_ty) = ty.builtin_deref(true)
                     && pointee_ty.is_freeze(self.tcx, self.typing_env())
                 {

From 1787789fe5b1eb9f37e72abaff933cd38f68e813 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 6/9] Bless tests

---
 tests/coverage/closure.cov-map                |  18 +-
 tests/coverage/issue-84561.cov-map            | 163 +++++-------
 .../read_immutable_static.main.GVN.diff       |  14 +-
 .../const_prop/read_immutable_static.rs       |   2 +-
 .../const_prop/ref_deref.main.GVN.diff        |   3 +-
 .../ref_deref_project.main.GVN.diff           |   3 +-
 tests/mir-opt/const_prop/ref_deref_project.rs |   2 +-
 .../slice_len.main.GVN.32bit.panic-abort.diff |   2 +-
 ...slice_len.main.GVN.32bit.panic-unwind.diff |   2 +-
 .../slice_len.main.GVN.64bit.panic-abort.diff |   2 +-
 ...slice_len.main.GVN.64bit.panic-unwind.diff |   2 +-
 tests/mir-opt/const_prop/slice_len.rs         |   4 +-
 .../mir-opt/gvn.borrowed.GVN.panic-abort.diff |   3 +-
 .../gvn.borrowed.GVN.panic-unwind.diff        |   3 +-
 tests/mir-opt/gvn.rs                          |   2 +-
 tests/mir-opt/gvn.slices.GVN.panic-abort.diff |  38 +--
 .../mir-opt/gvn.slices.GVN.panic-unwind.diff  |  38 +--
 .../gvn_uninhabited.f.GVN.panic-abort.diff    |  15 +-
 .../gvn_uninhabited.f.GVN.panic-unwind.diff   |  15 +-
 ...variant_a-{closure#0}.PreCodegen.after.mir | 238 ++++++++----------
 ...variant_b-{closure#0}.PreCodegen.after.mir |  54 ++--
 21 files changed, 301 insertions(+), 322 deletions(-)

diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
index 640f9895684..2d784ba09b6 100644
--- a/tests/coverage/closure.cov-map
+++ b/tests/coverage/closure.cov-map
@@ -140,17 +140,19 @@ Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 Highest counter ID seen: c1
 
-Function name: closure::main::{closure#18} (unused)
-Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 11, 00, 12, 00, 01, 11, 01, 0e]
+Function name: closure::main::{closure#18}
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 19, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 0
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 4
-- Code(Zero) at (prev + 25, 13) to (start + 2, 28)
-- Code(Zero) at (prev + 2, 29) to (start + 2, 18)
-- Code(Zero) at (prev + 2, 17) to (start + 0, 18)
-- Code(Zero) at (prev + 1, 17) to (start + 1, 14)
-Highest counter ID seen: (none)
+- Code(Counter(0)) at (prev + 25, 13) to (start + 2, 28)
+- Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
+- Code(Expression(0, Sub)) at (prev + 2, 17) to (start + 0, 18)
+    = (c0 - c1)
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14)
+Highest counter ID seen: c1
 
 Function name: closure::main::{closure#19}
 Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 11, 00, 12, 01, 01, 11, 01, 0e]
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index 3bd4e7d2a36..47e2922a805 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -59,109 +59,80 @@ Number of file 0 mappings: 1
 Highest counter ID seen: c0
 
 Function name: issue_84561::test3
-Raw bytes (315): 0x[01, 01, 1b, 1d, 21, 25, 29, 21, 25, 2d, 31, 21, 17, 25, 2d, 41, 45, 49, 4d, 51, 55, 33, 51, 49, 4d, 33, 37, 49, 4d, 51, 59, 55, 59, 55, 59, 47, 5d, 55, 59, 61, 65, 71, 75, 69, 6d, 69, 6d, 69, 6d, 63, 79, 71, 75, 79, 7d, 7d, 81, 01, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 0d, 05, 05, 00, 0f, 11, 01, 05, 00, 0f, 15, 01, 09, 01, 0f, 19, 02, 05, 00, 0f, 1d, 01, 05, 00, 0f, 02, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 25, 03, 20, 00, 30, 29, 00, 33, 00, 41, 06, 00, 4b, 00, 5a, 0a, 01, 05, 00, 0f, 2d, 05, 09, 03, 10, 31, 05, 0d, 00, 1b, 0e, 02, 0d, 00, 1c, 12, 04, 09, 02, 0f, 35, 06, 05, 00, 0f, 39, 04, 05, 00, 0f, 3d, 04, 09, 01, 0f, 41, 05, 08, 00, 0f, 45, 01, 09, 00, 13, 1a, 05, 09, 00, 13, 33, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 22, 03, 0d, 00, 1d, 26, 03, 09, 00, 13, 2e, 03, 0d, 00, 1d, 47, 03, 05, 00, 0f, 47, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 42, 02, 0d, 00, 13, 61, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 4a, 02, 0d, 00, 13, 63, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 00, 17, 71, 04, 0d, 00, 13, 5a, 02, 0d, 00, 17, 5a, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 5a, 02, 15, 00, 1b, 75, 04, 0d, 00, 13, 5e, 03, 09, 00, 19, 79, 02, 05, 00, 0f, 66, 03, 09, 00, 22, 7d, 02, 05, 00, 0f, 6a, 03, 09, 00, 2c, 81, 01, 02, 01, 00, 02]
+Raw bytes (279): 0x[01, 01, 0a, 0d, 11, 0d, 15, 0d, 19, 1d, 21, 29, 2d, 25, 29, 25, 29, 25, 29, 27, 31, 29, 2d, 33, 01, 08, 01, 03, 0f, 05, 04, 09, 01, 0f, 09, 02, 05, 04, 0f, 09, 05, 05, 00, 0f, 09, 01, 05, 00, 0f, 09, 01, 09, 01, 0f, 0d, 02, 05, 00, 0f, 0d, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 0d, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 0d, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 0d, 04, 09, 02, 0f, 0d, 06, 05, 00, 0f, 0d, 04, 05, 00, 0f, 0d, 04, 09, 01, 0f, 0d, 05, 08, 00, 0f, 11, 01, 09, 00, 13, 02, 05, 09, 00, 13, 0d, 05, 08, 00, 0f, 15, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 06, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 0d, 03, 05, 00, 0f, 0d, 01, 0c, 00, 13, 19, 01, 0d, 00, 13, 0a, 02, 0d, 00, 13, 1d, 04, 05, 02, 13, 21, 03, 0d, 00, 13, 0e, 02, 0d, 00, 13, 27, 03, 05, 00, 0f, 25, 01, 0c, 00, 13, 29, 01, 0d, 00, 17, 29, 04, 0d, 00, 13, 1e, 02, 0d, 00, 17, 1e, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 1e, 02, 15, 00, 1b, 2d, 04, 0d, 00, 13, 22, 03, 09, 00, 19, 31, 02, 05, 00, 0f, 31, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 27
-- expression 0 operands: lhs = Counter(7), rhs = Counter(8)
-- expression 1 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 2 operands: lhs = Counter(8), rhs = Counter(9)
-- expression 3 operands: lhs = Counter(11), rhs = Counter(12)
-- expression 4 operands: lhs = Counter(8), rhs = Expression(5, Add)
-- expression 5 operands: lhs = Counter(9), rhs = Counter(11)
-- expression 6 operands: lhs = Counter(16), rhs = Counter(17)
-- expression 7 operands: lhs = Counter(18), rhs = Counter(19)
-- expression 8 operands: lhs = Counter(20), rhs = Counter(21)
-- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(20)
-- expression 10 operands: lhs = Counter(18), rhs = Counter(19)
-- expression 11 operands: lhs = Expression(12, Add), rhs = Expression(13, Add)
-- expression 12 operands: lhs = Counter(18), rhs = Counter(19)
-- expression 13 operands: lhs = Counter(20), rhs = Counter(22)
-- expression 14 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 15 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(23)
-- expression 17 operands: lhs = Counter(21), rhs = Counter(22)
-- expression 18 operands: lhs = Counter(24), rhs = Counter(25)
-- expression 19 operands: lhs = Counter(28), rhs = Counter(29)
-- expression 20 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 21 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 22 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(30)
-- expression 24 operands: lhs = Counter(28), rhs = Counter(29)
-- expression 25 operands: lhs = Counter(30), rhs = Counter(31)
-- expression 26 operands: lhs = Counter(31), rhs = Counter(32)
+Number of expressions: 10
+- expression 0 operands: lhs = Counter(3), rhs = Counter(4)
+- expression 1 operands: lhs = Counter(3), rhs = Counter(5)
+- expression 2 operands: lhs = Counter(3), rhs = Counter(6)
+- expression 3 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 4 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 5 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 6 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 7 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(12)
+- expression 9 operands: lhs = Counter(10), rhs = Counter(11)
 Number of file 0 mappings: 51
 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 15)
 - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 15)
 - Code(Counter(2)) at (prev + 2, 5) to (start + 4, 15)
-- Code(Counter(3)) at (prev + 5, 5) to (start + 0, 15)
-- Code(Counter(4)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Counter(5)) at (prev + 1, 9) to (start + 1, 15)
-- Code(Counter(6)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Counter(7)) at (prev + 1, 5) to (start + 0, 15)
-- Code(Expression(0, Sub)) at (prev + 0, 32) to (start + 0, 48)
+- Code(Counter(2)) at (prev + 5, 5) to (start + 0, 15)
+- Code(Counter(2)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
+- Code(Counter(3)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Zero) at (prev + 0, 32) to (start + 0, 48)
+- Code(Counter(3)) at (prev + 1, 5) to (start + 3, 15)
+- Code(Zero) at (prev + 3, 32) to (start + 0, 48)
+- Code(Zero) at (prev + 0, 51) to (start + 0, 65)
+- Code(Zero) at (prev + 0, 75) to (start + 0, 90)
+- Code(Counter(3)) at (prev + 1, 5) to (start + 0, 15)
+- Code(Zero) at (prev + 5, 9) to (start + 3, 16)
+- Code(Zero) at (prev + 5, 13) to (start + 0, 27)
+- Code(Zero) at (prev + 2, 13) to (start + 0, 28)
+- Code(Counter(3)) at (prev + 4, 9) to (start + 2, 15)
+- Code(Counter(3)) at (prev + 6, 5) to (start + 0, 15)
+- Code(Counter(3)) at (prev + 4, 5) to (start + 0, 15)
+- Code(Counter(3)) at (prev + 4, 9) to (start + 1, 15)
+- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15)
+- Code(Counter(4)) at (prev + 1, 9) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 5, 9) to (start + 0, 19)
+    = (c3 - c4)
+- Code(Counter(3)) at (prev + 5, 8) to (start + 0, 15)
+- Code(Counter(5)) at (prev + 1, 9) to (start + 0, 19)
+- Code(Zero) at (prev + 3, 13) to (start + 0, 29)
+- Code(Expression(1, Sub)) at (prev + 3, 9) to (start + 0, 19)
+    = (c3 - c5)
+- Code(Zero) at (prev + 3, 13) to (start + 0, 29)
+- Code(Counter(3)) at (prev + 3, 5) to (start + 0, 15)
+- Code(Counter(3)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Counter(6)) at (prev + 1, 13) to (start + 0, 19)
+- Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 19)
+    = (c3 - c6)
+- Code(Counter(7)) at (prev + 4, 5) to (start + 2, 19)
+- Code(Counter(8)) at (prev + 3, 13) to (start + 0, 19)
+- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 19)
     = (c7 - c8)
-- Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15)
-- Code(Counter(9)) at (prev + 3, 32) to (start + 0, 48)
-- Code(Counter(10)) at (prev + 0, 51) to (start + 0, 65)
-- Code(Expression(1, Sub)) at (prev + 0, 75) to (start + 0, 90)
+- Code(Expression(9, Add)) at (prev + 3, 5) to (start + 0, 15)
+    = (c10 + c11)
+- Code(Counter(9)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Counter(10)) at (prev + 1, 13) to (start + 0, 23)
+- Code(Counter(10)) at (prev + 4, 13) to (start + 0, 19)
+- Code(Expression(7, Sub)) at (prev + 2, 13) to (start + 0, 23)
+    = (c9 - c10)
+- Code(Expression(7, Sub)) at (prev + 1, 20) to (start + 0, 27)
     = (c9 - c10)
-- Code(Expression(2, Sub)) at (prev + 1, 5) to (start + 0, 15)
-    = (c8 - c9)
-- Code(Counter(11)) at (prev + 5, 9) to (start + 3, 16)
-- Code(Counter(12)) at (prev + 5, 13) to (start + 0, 27)
-- Code(Expression(3, Sub)) at (prev + 2, 13) to (start + 0, 28)
-    = (c11 - c12)
-- Code(Expression(4, Sub)) at (prev + 4, 9) to (start + 2, 15)
-    = (c8 - (c9 + c11))
-- Code(Counter(13)) at (prev + 6, 5) to (start + 0, 15)
-- Code(Counter(14)) at (prev + 4, 5) to (start + 0, 15)
-- Code(Counter(15)) at (prev + 4, 9) to (start + 1, 15)
-- Code(Counter(16)) at (prev + 5, 8) to (start + 0, 15)
-- Code(Counter(17)) at (prev + 1, 9) to (start + 0, 19)
-- Code(Expression(6, Sub)) at (prev + 5, 9) to (start + 0, 19)
-    = (c16 - c17)
-- Code(Expression(12, Add)) at (prev + 5, 8) to (start + 0, 15)
-    = (c18 + c19)
-- Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19)
-- Code(Expression(8, Sub)) at (prev + 3, 13) to (start + 0, 29)
-    = (c20 - c21)
-- Code(Expression(9, Sub)) at (prev + 3, 9) to (start + 0, 19)
-    = ((c18 + c19) - c20)
-- Code(Expression(11, Sub)) at (prev + 3, 13) to (start + 0, 29)
-    = ((c18 + c19) - (c20 + c22))
-- Code(Expression(17, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c21 + c22)
-- Code(Expression(17, Add)) at (prev + 1, 12) to (start + 0, 19)
-    = (c21 + c22)
-- Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19)
-- Code(Expression(16, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = ((c21 + c22) - c23)
-- Code(Counter(24)) at (prev + 4, 5) to (start + 2, 19)
-- Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19)
-- Code(Expression(18, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (c24 - c25)
-- Code(Expression(24, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c28 + c29)
-- Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19)
-- Code(Counter(27)) at (prev + 1, 13) to (start + 0, 23)
-- Code(Counter(28)) at (prev + 4, 13) to (start + 0, 19)
-- Code(Expression(22, Sub)) at (prev + 2, 13) to (start + 0, 23)
-    = (c26 - c27)
-- Code(Expression(22, Sub)) at (prev + 1, 20) to (start + 0, 27)
-    = (c26 - c27)
 - Code(Zero) at (prev + 1, 21) to (start + 0, 27)
-- Code(Expression(22, Sub)) at (prev + 2, 21) to (start + 0, 27)
-    = (c26 - c27)
-- Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19)
-- Code(Expression(23, Sub)) at (prev + 3, 9) to (start + 0, 25)
-    = ((c28 + c29) - c30)
-- Code(Counter(30)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Expression(25, Sub)) at (prev + 3, 9) to (start + 0, 34)
-    = (c30 - c31)
-- Code(Counter(31)) at (prev + 2, 5) to (start + 0, 15)
-- Code(Expression(26, Sub)) at (prev + 3, 9) to (start + 0, 44)
-    = (c31 - c32)
-- Code(Counter(32)) at (prev + 2, 1) to (start + 0, 2)
-Highest counter ID seen: c32
+- Code(Expression(7, Sub)) at (prev + 2, 21) to (start + 0, 27)
+    = (c9 - c10)
+- Code(Counter(11)) at (prev + 4, 13) to (start + 0, 19)
+- Code(Expression(8, Sub)) at (prev + 3, 9) to (start + 0, 25)
+    = ((c10 + c11) - c12)
+- Code(Counter(12)) at (prev + 2, 5) to (start + 0, 15)
+- Code(Counter(12)) at (prev + 3, 9) to (start + 0, 34)
+- Code(Zero) at (prev + 2, 5) to (start + 0, 15)
+- Code(Zero) at (prev + 3, 9) to (start + 0, 44)
+- Code(Zero) at (prev + 2, 1) to (start + 0, 2)
+Highest counter ID seen: c12
 
diff --git a/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff
index 23928337bf7..8df262b351f 100644
--- a/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff
+++ b/tests/mir-opt/const_prop/read_immutable_static.main.GVN.diff
@@ -14,19 +14,23 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
+-         StorageLive(_2);
 -         StorageLive(_3);
++         nop;
 +         nop;
           _3 = const {ALLOC0: &u8};
-          _2 = copy (*_3);
+-         _2 = copy (*_3);
++         _2 = const 2_u8;
           StorageLive(_4);
           StorageLive(_5);
           _5 = const {ALLOC0: &u8};
 -         _4 = copy (*_5);
-+         _4 = copy (*_3);
-          _1 = Add(move _2, move _4);
+-         _1 = Add(move _2, move _4);
++         _4 = const 2_u8;
++         _1 = const 4_u8;
           StorageDead(_4);
-          StorageDead(_2);
+-         StorageDead(_2);
++         nop;
           StorageDead(_5);
 -         StorageDead(_3);
 +         nop;
diff --git a/tests/mir-opt/const_prop/read_immutable_static.rs b/tests/mir-opt/const_prop/read_immutable_static.rs
index f88e4b3de93..05fec2f3303 100644
--- a/tests/mir-opt/const_prop/read_immutable_static.rs
+++ b/tests/mir-opt/const_prop/read_immutable_static.rs
@@ -6,6 +6,6 @@ static FOO: u8 = 2;
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug x => [[x:_.*]];
-    // CHECK-NOT: [[x]] = const 4_u8;
+    // CHECK: [[x]] = const 4_u8;
     let x = FOO + FOO;
 }
diff --git a/tests/mir-opt/const_prop/ref_deref.main.GVN.diff b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff
index 4477b4b005b..b9e269266b0 100644
--- a/tests/mir-opt/const_prop/ref_deref.main.GVN.diff
+++ b/tests/mir-opt/const_prop/ref_deref.main.GVN.diff
@@ -16,7 +16,8 @@
           StorageLive(_2);
           _4 = const main::promoted[0];
           _2 = &(*_4);
-          _1 = copy (*_2);
+-         _1 = copy (*_2);
++         _1 = const 4_i32;
           StorageDead(_2);
           _0 = const ();
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff
index bbfd70bea16..dcc13c9251c 100644
--- a/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff
+++ b/tests/mir-opt/const_prop/ref_deref_project.main.GVN.diff
@@ -16,7 +16,8 @@
           StorageLive(_2);
           _4 = const main::promoted[0];
           _2 = &((*_4).1: i32);
-          _1 = copy (*_2);
+-         _1 = copy (*_2);
++         _1 = const 5_i32;
           StorageDead(_2);
           _0 = const ();
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/ref_deref_project.rs b/tests/mir-opt/const_prop/ref_deref_project.rs
index 813b4ae4745..5a48a887f93 100644
--- a/tests/mir-opt/const_prop/ref_deref_project.rs
+++ b/tests/mir-opt/const_prop/ref_deref_project.rs
@@ -5,6 +5,6 @@
 fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
-    // CHECK-NOT: [[a]] = const 5_i32;
+    // CHECK: [[a]] = const 5_i32;
     let a = *(&(4, 5).1);
 }
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
index 0798b303929..d6e81debccd 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-abort.diff
@@ -40,7 +40,7 @@
   
       bb1: {
 -         _1 = copy (*_2)[_6];
-+         _1 = copy (*_2)[1 of 2];
++         _1 = const 2_u32;
           StorageDead(_6);
           StorageDead(_4);
           StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
index c0b3d4d3219..6713e531892 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.32bit.panic-unwind.diff
@@ -40,7 +40,7 @@
   
       bb1: {
 -         _1 = copy (*_2)[_6];
-+         _1 = copy (*_2)[1 of 2];
++         _1 = const 2_u32;
           StorageDead(_6);
           StorageDead(_4);
           StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
index 0798b303929..d6e81debccd 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-abort.diff
@@ -40,7 +40,7 @@
   
       bb1: {
 -         _1 = copy (*_2)[_6];
-+         _1 = copy (*_2)[1 of 2];
++         _1 = const 2_u32;
           StorageDead(_6);
           StorageDead(_4);
           StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
index c0b3d4d3219..6713e531892 100644
--- a/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/slice_len.main.GVN.64bit.panic-unwind.diff
@@ -40,7 +40,7 @@
   
       bb1: {
 -         _1 = copy (*_2)[_6];
-+         _1 = copy (*_2)[1 of 2];
++         _1 = const 2_u32;
           StorageDead(_6);
           StorageDead(_4);
           StorageDead(_2);
diff --git a/tests/mir-opt/const_prop/slice_len.rs b/tests/mir-opt/const_prop/slice_len.rs
index eb86e28408a..ebd3c9e792d 100644
--- a/tests/mir-opt/const_prop/slice_len.rs
+++ b/tests/mir-opt/const_prop/slice_len.rs
@@ -8,7 +8,7 @@ fn main() {
     // CHECK-LABEL: fn main(
     // CHECK: debug a => [[a:_.*]];
     // CHECK: [[slice:_.*]] = copy {{.*}} as &[u32] (PointerCoercion(Unsize, AsCast));
-    // CHECK-NOT: assert(const true,
-    // CHECK-NOT: [[a]] = const 2_u32;
+    // CHECK: assert(const true,
+    // CHECK: [[a]] = const 2_u32;
     let a = (&[1u32, 2, 3] as &[u32])[1];
 }
diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff
index acbea13642c..b0702696e18 100644
--- a/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff
@@ -18,7 +18,8 @@
       }
   
       bb2: {
-          _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
+-         _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind unreachable];
++         _0 = opaque::<T>(copy _1) -> [return: bb3, unwind unreachable];
       }
   
       bb3: {
diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff
index ba080bfdb07..fe05d4deeed 100644
--- a/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff
@@ -18,7 +18,8 @@
       }
   
       bb2: {
-          _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
+-         _0 = opaque::<T>(copy (*_3)) -> [return: bb3, unwind continue];
++         _0 = opaque::<T>(copy _1) -> [return: bb3, unwind continue];
       }
   
       bb3: {
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index be97470ebb1..6ef320c90de 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -742,7 +742,7 @@ fn borrowed<T: Copy + Freeze>(x: T) {
     // CHECK: bb1: {
     // CHECK-NEXT: _0 = opaque::<T>(copy _1)
     // CHECK: bb2: {
-    // CHECK-NEXT: _0 = opaque::<T>(copy (*_3))
+    // CHECK-NEXT: _0 = opaque::<T>(copy _1)
     mir! {
         {
             let a = x;
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
index 43efcbdfb1e..e8e99b44e72 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
@@ -111,8 +111,9 @@
           StorageLive(_7);
           StorageLive(_8);
 -         StorageLive(_9);
+-         StorageLive(_10);
++         nop;
 +         nop;
-          StorageLive(_10);
           StorageLive(_11);
           _11 = &(*_1);
           _10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind unreachable];
@@ -122,8 +123,9 @@
           StorageDead(_11);
           _9 = &_10;
 -         StorageLive(_12);
+-         StorageLive(_13);
++         nop;
 +         nop;
-          StorageLive(_13);
           StorageLive(_14);
 -         _14 = &(*_4);
 +         _14 = &(*_1);
@@ -148,11 +150,12 @@
           StorageLive(_17);
           StorageLive(_18);
 -         _18 = copy (*_15);
-+         _18 = copy (*_9);
++         _18 = copy _10;
           StorageLive(_19);
 -         _19 = copy (*_16);
-+         _19 = copy (*_12);
-          _17 = Eq(move _18, move _19);
+-         _17 = Eq(move _18, move _19);
++         _19 = copy _13;
++         _17 = Eq(copy _10, copy _13);
           switchInt(move _17) -> [0: bb6, otherwise: bb5];
       }
   
@@ -163,8 +166,10 @@
           StorageDead(_17);
           StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_13);
-          StorageDead(_10);
+-         StorageDead(_13);
+-         StorageDead(_10);
++         nop;
++         nop;
           StorageDead(_8);
           StorageDead(_7);
 -         StorageLive(_29);
@@ -213,8 +218,9 @@
           StorageLive(_33);
           StorageLive(_34);
 -         StorageLive(_35);
+-         StorageLive(_36);
++         nop;
 +         nop;
-          StorageLive(_36);
           StorageLive(_37);
           _37 = &(*_1);
           _36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind unreachable];
@@ -224,8 +230,9 @@
           StorageDead(_37);
           _35 = &_36;
 -         StorageLive(_38);
+-         StorageLive(_39);
++         nop;
 +         nop;
-          StorageLive(_39);
           StorageLive(_40);
           _40 = &(*_29);
           _39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind unreachable];
@@ -249,11 +256,12 @@
           StorageLive(_43);
           StorageLive(_44);
 -         _44 = copy (*_41);
-+         _44 = copy (*_35);
++         _44 = copy _36;
           StorageLive(_45);
 -         _45 = copy (*_42);
-+         _45 = copy (*_38);
-          _43 = Eq(move _44, move _45);
+-         _43 = Eq(move _44, move _45);
++         _45 = copy _39;
++         _43 = Eq(copy _36, copy _39);
           switchInt(move _43) -> [0: bb11, otherwise: bb10];
       }
   
@@ -264,8 +272,10 @@
           StorageDead(_43);
           StorageDead(_42);
           StorageDead(_41);
-          StorageDead(_39);
-          StorageDead(_36);
+-         StorageDead(_39);
+-         StorageDead(_36);
++         nop;
++         nop;
           StorageDead(_34);
           StorageDead(_33);
           _0 = const ();
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
index 8572f538c0f..4296d4d4a59 100644
--- a/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.slices.GVN.panic-unwind.diff
@@ -111,8 +111,9 @@
           StorageLive(_7);
           StorageLive(_8);
 -         StorageLive(_9);
+-         StorageLive(_10);
++         nop;
 +         nop;
-          StorageLive(_10);
           StorageLive(_11);
           _11 = &(*_1);
           _10 = core::str::<impl str>::as_ptr(move _11) -> [return: bb3, unwind continue];
@@ -122,8 +123,9 @@
           StorageDead(_11);
           _9 = &_10;
 -         StorageLive(_12);
+-         StorageLive(_13);
++         nop;
 +         nop;
-          StorageLive(_13);
           StorageLive(_14);
 -         _14 = &(*_4);
 +         _14 = &(*_1);
@@ -148,11 +150,12 @@
           StorageLive(_17);
           StorageLive(_18);
 -         _18 = copy (*_15);
-+         _18 = copy (*_9);
++         _18 = copy _10;
           StorageLive(_19);
 -         _19 = copy (*_16);
-+         _19 = copy (*_12);
-          _17 = Eq(move _18, move _19);
+-         _17 = Eq(move _18, move _19);
++         _19 = copy _13;
++         _17 = Eq(copy _10, copy _13);
           switchInt(move _17) -> [0: bb6, otherwise: bb5];
       }
   
@@ -163,8 +166,10 @@
           StorageDead(_17);
           StorageDead(_16);
           StorageDead(_15);
-          StorageDead(_13);
-          StorageDead(_10);
+-         StorageDead(_13);
+-         StorageDead(_10);
++         nop;
++         nop;
           StorageDead(_8);
           StorageDead(_7);
 -         StorageLive(_29);
@@ -213,8 +218,9 @@
           StorageLive(_33);
           StorageLive(_34);
 -         StorageLive(_35);
+-         StorageLive(_36);
++         nop;
 +         nop;
-          StorageLive(_36);
           StorageLive(_37);
           _37 = &(*_1);
           _36 = core::str::<impl str>::as_ptr(move _37) -> [return: bb8, unwind continue];
@@ -224,8 +230,9 @@
           StorageDead(_37);
           _35 = &_36;
 -         StorageLive(_38);
+-         StorageLive(_39);
++         nop;
 +         nop;
-          StorageLive(_39);
           StorageLive(_40);
           _40 = &(*_29);
           _39 = core::slice::<impl [u8]>::as_ptr(move _40) -> [return: bb9, unwind continue];
@@ -249,11 +256,12 @@
           StorageLive(_43);
           StorageLive(_44);
 -         _44 = copy (*_41);
-+         _44 = copy (*_35);
++         _44 = copy _36;
           StorageLive(_45);
 -         _45 = copy (*_42);
-+         _45 = copy (*_38);
-          _43 = Eq(move _44, move _45);
+-         _43 = Eq(move _44, move _45);
++         _45 = copy _39;
++         _43 = Eq(copy _36, copy _39);
           switchInt(move _43) -> [0: bb11, otherwise: bb10];
       }
   
@@ -264,8 +272,10 @@
           StorageDead(_43);
           StorageDead(_42);
           StorageDead(_41);
-          StorageDead(_39);
-          StorageDead(_36);
+-         StorageDead(_39);
+-         StorageDead(_36);
++         nop;
++         nop;
           StorageDead(_34);
           StorageDead(_33);
           _0 = const ();
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
index 881b629803a..a3e4796d088 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
@@ -17,15 +17,16 @@
           StorageLive(_3);
           _5 = const f::promoted[0];
           _3 = &(*_5);
-          _2 = copy ((*_3).1: E);
--         StorageLive(_1);
-+         nop;
-          _1 = copy ((_2 as A).1: u32);
+-         _2 = copy ((*_3).1: E);
++         _2 = const Scalar(0x00000000): E;
+          StorageLive(_1);
+-         _1 = copy ((_2 as A).1: u32);
++         _1 = const 0_u32;
           StorageDead(_3);
           StorageDead(_2);
-          _0 = copy _1;
--         StorageDead(_1);
-+         nop;
+-         _0 = copy _1;
++         _0 = const 0_u32;
+          StorageDead(_1);
           return;
       }
   }
diff --git a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
index 881b629803a..a3e4796d088 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
@@ -17,15 +17,16 @@
           StorageLive(_3);
           _5 = const f::promoted[0];
           _3 = &(*_5);
-          _2 = copy ((*_3).1: E);
--         StorageLive(_1);
-+         nop;
-          _1 = copy ((_2 as A).1: u32);
+-         _2 = copy ((*_3).1: E);
++         _2 = const Scalar(0x00000000): E;
+          StorageLive(_1);
+-         _1 = copy ((_2 as A).1: u32);
++         _1 = const 0_u32;
           StorageDead(_3);
           StorageDead(_2);
-          _0 = copy _1;
--         StorageDead(_1);
-+         nop;
+-         _0 = copy _1;
++         _0 = const 0_u32;
+          StorageDead(_1);
           return;
       }
   }
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
index 5a269717f82..cbdd194afd3 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir
@@ -4,70 +4,65 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: &usize;
-    let mut _5: &(usize, usize, usize, usize);
+    let _5: &usize;
     let _6: &usize;
-    let mut _7: &(usize, usize, usize, usize);
-    let _8: &usize;
-    let mut _9: &(usize, usize, usize, usize);
-    let _10: &usize;
-    let mut _11: &&usize;
-    let _12: &usize;
-    let mut _13: &&usize;
-    let mut _16: bool;
-    let mut _17: &&usize;
-    let _18: &usize;
-    let mut _19: &&usize;
-    let mut _22: bool;
-    let mut _23: &&usize;
-    let _24: &usize;
-    let mut _25: &&usize;
-    let mut _28: bool;
-    let mut _29: &&usize;
-    let _30: &usize;
-    let mut _31: &&usize;
+    let _7: &usize;
+    let mut _8: &&usize;
+    let _9: &usize;
+    let mut _10: &&usize;
+    let mut _13: bool;
+    let mut _14: &&usize;
+    let _15: &usize;
+    let mut _16: &&usize;
+    let mut _19: bool;
+    let mut _20: &&usize;
+    let _21: &usize;
+    let mut _22: &&usize;
+    let mut _23: bool;
+    let mut _24: &&usize;
+    let _25: &usize;
+    let mut _26: &&usize;
     scope 1 {
         debug a => _4;
-        debug b => _6;
-        debug c => _8;
-        debug d => _10;
+        debug b => _5;
+        debug c => _6;
+        debug d => _7;
         scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _11;
-            debug other => _13;
+            debug self => _8;
+            debug other => _10;
             scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
                 debug self => _4;
-                debug other => _8;
-                let mut _14: usize;
-                let mut _15: usize;
+                debug other => _6;
+                let mut _11: usize;
+                let mut _12: usize;
             }
         }
         scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _17;
-            debug other => _19;
+            debug self => _14;
+            debug other => _16;
             scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _10;
-                debug other => _6;
-                let mut _20: usize;
-                let mut _21: usize;
+                debug self => _7;
+                debug other => _5;
+                let mut _17: usize;
+                let mut _18: usize;
             }
         }
         scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _23;
-            debug other => _25;
+            debug self => _20;
+            debug other => _22;
             scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _8;
+                debug self => _6;
                 debug other => _4;
-                let mut _26: usize;
-                let mut _27: usize;
             }
         }
         scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _29;
-            debug other => _31;
+            debug self => _24;
+            debug other => _26;
             scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _6;
-                debug other => _10;
-                let mut _32: usize;
-                let mut _33: usize;
+                debug self => _5;
+                debug other => _7;
+                let mut _27: usize;
+                let mut _28: usize;
             }
         }
     }
@@ -75,129 +70,116 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
     bb0: {
         _3 = copy (*_2);
         _4 = &((*_3).0: usize);
-        _5 = copy (*_2);
-        _6 = &((*_5).1: usize);
-        _7 = copy (*_2);
-        _8 = &((*_7).2: usize);
-        _9 = copy (*_2);
-        _10 = &((*_9).3: usize);
-        StorageLive(_16);
-        StorageLive(_11);
-        _11 = &_4;
+        _5 = &((*_3).1: usize);
+        _6 = &((*_3).2: usize);
+        _7 = &((*_3).3: usize);
         StorageLive(_13);
-        StorageLive(_12);
-        _12 = copy _8;
-        _13 = &_12;
-        StorageLive(_14);
-        _14 = copy ((*_3).0: usize);
-        StorageLive(_15);
-        _15 = copy ((*_7).2: usize);
-        _16 = Le(move _14, move _15);
-        StorageDead(_15);
-        StorageDead(_14);
-        switchInt(move _16) -> [0: bb1, otherwise: bb2];
+        StorageLive(_8);
+        _8 = &_4;
+        StorageLive(_10);
+        StorageLive(_9);
+        _9 = copy _6;
+        _10 = &_9;
+        _11 = copy ((*_3).0: usize);
+        _12 = copy ((*_3).2: usize);
+        _13 = Le(copy _11, copy _12);
+        switchInt(move _13) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageDead(_12);
-        StorageDead(_13);
-        StorageDead(_11);
+        StorageDead(_9);
+        StorageDead(_10);
+        StorageDead(_8);
         goto -> bb4;
     }
 
     bb2: {
-        StorageDead(_12);
-        StorageDead(_13);
-        StorageDead(_11);
-        StorageLive(_22);
-        StorageLive(_17);
-        _17 = &_10;
+        StorageDead(_9);
+        StorageDead(_10);
+        StorageDead(_8);
         StorageLive(_19);
+        StorageLive(_14);
+        _14 = &_7;
+        StorageLive(_16);
+        StorageLive(_15);
+        _15 = copy _5;
+        _16 = &_15;
+        StorageLive(_17);
+        _17 = copy ((*_3).3: usize);
         StorageLive(_18);
-        _18 = copy _6;
-        _19 = &_18;
-        StorageLive(_20);
-        _20 = copy ((*_9).3: usize);
-        StorageLive(_21);
-        _21 = copy ((*_5).1: usize);
-        _22 = Le(move _20, move _21);
-        StorageDead(_21);
-        StorageDead(_20);
-        switchInt(move _22) -> [0: bb3, otherwise: bb8];
+        _18 = copy ((*_3).1: usize);
+        _19 = Le(move _17, move _18);
+        StorageDead(_18);
+        StorageDead(_17);
+        switchInt(move _19) -> [0: bb3, otherwise: bb8];
     }
 
     bb3: {
-        StorageDead(_18);
-        StorageDead(_19);
-        StorageDead(_17);
+        StorageDead(_15);
+        StorageDead(_16);
+        StorageDead(_14);
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_28);
         StorageLive(_23);
-        _23 = &_8;
-        StorageLive(_25);
-        StorageLive(_24);
-        _24 = copy _4;
-        _25 = &_24;
-        StorageLive(_26);
-        _26 = copy ((*_7).2: usize);
-        StorageLive(_27);
-        _27 = copy ((*_3).0: usize);
-        _28 = Le(move _26, move _27);
-        StorageDead(_27);
-        StorageDead(_26);
-        switchInt(move _28) -> [0: bb5, otherwise: bb6];
+        StorageLive(_20);
+        _20 = &_6;
+        StorageLive(_22);
+        StorageLive(_21);
+        _21 = copy _4;
+        _22 = &_21;
+        _23 = Le(copy _12, copy _11);
+        switchInt(move _23) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
-        StorageDead(_24);
-        StorageDead(_25);
-        StorageDead(_23);
+        StorageDead(_21);
+        StorageDead(_22);
+        StorageDead(_20);
         _0 = const false;
         goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_24);
+        StorageDead(_21);
+        StorageDead(_22);
+        StorageDead(_20);
+        StorageLive(_24);
+        _24 = &_5;
+        StorageLive(_26);
+        StorageLive(_25);
+        _25 = copy _7;
+        _26 = &_25;
+        StorageLive(_27);
+        _27 = copy ((*_3).1: usize);
+        StorageLive(_28);
+        _28 = copy ((*_3).3: usize);
+        _0 = Le(move _27, move _28);
+        StorageDead(_28);
+        StorageDead(_27);
         StorageDead(_25);
-        StorageDead(_23);
-        StorageLive(_29);
-        _29 = &_6;
-        StorageLive(_31);
-        StorageLive(_30);
-        _30 = copy _10;
-        _31 = &_30;
-        StorageLive(_32);
-        _32 = copy ((*_5).1: usize);
-        StorageLive(_33);
-        _33 = copy ((*_9).3: usize);
-        _0 = Le(move _32, move _33);
-        StorageDead(_33);
-        StorageDead(_32);
-        StorageDead(_30);
-        StorageDead(_31);
-        StorageDead(_29);
+        StorageDead(_26);
+        StorageDead(_24);
         goto -> bb7;
     }
 
     bb7: {
-        StorageDead(_28);
+        StorageDead(_23);
         goto -> bb9;
     }
 
     bb8: {
-        StorageDead(_18);
-        StorageDead(_19);
-        StorageDead(_17);
+        StorageDead(_15);
+        StorageDead(_16);
+        StorageDead(_14);
         _0 = const true;
         goto -> bb9;
     }
 
     bb9: {
-        StorageDead(_22);
-        StorageDead(_16);
+        StorageDead(_19);
+        StorageDead(_13);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
index f93f7264dec..bc7a31d5219 100644
--- a/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/slice_filter.variant_b-{closure#0}.PreCodegen.after.mir
@@ -4,46 +4,40 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
     let mut _0: bool;
     let mut _3: &(usize, usize, usize, usize);
     let _4: usize;
-    let mut _5: &(usize, usize, usize, usize);
+    let _5: usize;
     let _6: usize;
-    let mut _7: &(usize, usize, usize, usize);
-    let _8: usize;
-    let mut _9: &(usize, usize, usize, usize);
-    let _10: usize;
-    let mut _11: bool;
-    let mut _12: bool;
-    let mut _13: bool;
+    let _7: usize;
+    let mut _8: bool;
+    let mut _9: bool;
+    let mut _10: bool;
     scope 1 {
         debug a => _4;
-        debug b => _6;
-        debug c => _8;
-        debug d => _10;
+        debug b => _5;
+        debug c => _6;
+        debug d => _7;
     }
 
     bb0: {
         _3 = copy (*_2);
         _4 = copy ((*_3).0: usize);
-        _5 = copy (*_2);
-        _6 = copy ((*_5).1: usize);
-        _7 = copy (*_2);
-        _8 = copy ((*_7).2: usize);
-        _9 = copy (*_2);
-        _10 = copy ((*_9).3: usize);
-        StorageLive(_11);
-        _11 = Le(copy _4, copy _8);
-        switchInt(move _11) -> [0: bb2, otherwise: bb1];
+        _5 = copy ((*_3).1: usize);
+        _6 = copy ((*_3).2: usize);
+        _7 = copy ((*_3).3: usize);
+        StorageLive(_8);
+        _8 = Le(copy _4, copy _6);
+        switchInt(move _8) -> [0: bb2, otherwise: bb1];
     }
 
     bb1: {
-        StorageLive(_12);
-        _12 = Le(copy _10, copy _6);
-        switchInt(move _12) -> [0: bb2, otherwise: bb6];
+        StorageLive(_9);
+        _9 = Le(copy _7, copy _5);
+        switchInt(move _9) -> [0: bb2, otherwise: bb6];
     }
 
     bb2: {
-        StorageLive(_13);
-        _13 = Le(copy _8, copy _4);
-        switchInt(move _13) -> [0: bb3, otherwise: bb4];
+        StorageLive(_10);
+        _10 = Le(copy _6, copy _4);
+        switchInt(move _10) -> [0: bb3, otherwise: bb4];
     }
 
     bb3: {
@@ -52,12 +46,12 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
     }
 
     bb4: {
-        _0 = Le(copy _6, copy _10);
+        _0 = Le(copy _5, copy _7);
         goto -> bb5;
     }
 
     bb5: {
-        StorageDead(_13);
+        StorageDead(_10);
         goto -> bb7;
     }
 
@@ -67,8 +61,8 @@ fn variant_b::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:11:25: 11:41},
     }
 
     bb7: {
-        StorageDead(_12);
-        StorageDead(_11);
+        StorageDead(_9);
+        StorageDead(_8);
         return;
     }
 }

From ac7dd7a1b3307ddfd6ad95a1b3f58830e0fdbf65 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 7/9] Remove `unsound-mir-opts` for
 `simplify_aggregate_to_copy`

---
 compiler/rustc_mir_transform/src/gvn.rs       |  4 +-
 tests/codegen/clone_as_copy.rs                |  2 -
 tests/codegen/try_question_mark_nop.rs        | 38 ++++++++-----
 tests/mir-opt/gvn_clone.rs                    |  2 -
 .../mir-opt/gvn_clone.{impl#0}-clone.GVN.diff |  6 +--
 tests/mir-opt/gvn_copy_aggregate.rs           |  2 -
 tests/mir-opt/pre-codegen/clone_as_copy.rs    |  2 -
 ..._clone.{impl#0}-clone.PreCodegen.after.mir |  6 +--
 .../try_identity.old.PreCodegen.after.mir     |  8 +--
 ..._aggregate_to_copy_miscompile.foo.GVN.diff | 54 ++++++++-----------
 .../simplify_aggregate_to_copy_miscompile.rs  | 12 +++--
 11 files changed, 65 insertions(+), 71 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index a93fdff5817..b6294f4ff8a 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1098,9 +1098,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
-        // unsound: https://github.com/rust-lang/rust/issues/132353
-        if tcx.sess.opts.unstable_opts.unsound_mir_opts
-            && let AggregateTy::Def(_, _) = ty
+        if let AggregateTy::Def(_, _) = ty
             && let Some(value) =
                 self.simplify_aggregate_to_copy(rvalue, location, &fields, variant_index)
         {
diff --git a/tests/codegen/clone_as_copy.rs b/tests/codegen/clone_as_copy.rs
index c39f120044c..ef834ef5912 100644
--- a/tests/codegen/clone_as_copy.rs
+++ b/tests/codegen/clone_as_copy.rs
@@ -1,6 +1,4 @@
 //@ revisions: DEBUGINFO NODEBUGINFO
-//@ compile-flags: -Zunsound-mir-opts
-// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
 //@ compile-flags: -Copt-level=3 -Cno-prepopulate-passes
 //@ [DEBUGINFO] compile-flags: -Cdebuginfo=full
 
diff --git a/tests/codegen/try_question_mark_nop.rs b/tests/codegen/try_question_mark_nop.rs
index 3a3453b22b4..9430465a286 100644
--- a/tests/codegen/try_question_mark_nop.rs
+++ b/tests/codegen/try_question_mark_nop.rs
@@ -16,12 +16,17 @@ use std::ptr::NonNull;
 #[no_mangle]
 pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> {
     // CHECK: start:
-    // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1
-    // TWENTY-NEXT: %[[PAYLOAD:.+]] = select i1 %[[IS_SOME]], i32 %1, i32 undef
-    // CHECK-NEXT: [[REG1:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
-    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %1, 1
-    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } [[REG1]], i32 %[[PAYLOAD]], 1
-    // CHECK-NEXT: ret { i32, i32 } [[REG2]]
+    // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1
+
+    // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0
+    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0
+    // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1
+
+    // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef
+    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0
+    // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1
+
+    // CHECK-NEXT: ret { i32, i32 } [[REG3]]
     match x {
         Some(x) => Some(x),
         None => None,
@@ -90,12 +95,17 @@ pub fn control_flow_nop_traits_32(x: ControlFlow<i32, u32>) -> ControlFlow<i32,
 #[no_mangle]
 pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> {
     // CHECK: start:
-    // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1
-    // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef
-    // CHECK-NEXT: [[REG1:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } poison, i64 %0, 0
-    // NINETEEN-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %1, 1
-    // TWENTY-NEXT: [[REG2:%[0-9a-zA-Z_.]+]] = insertvalue { i64, i64 } [[REG1]], i64 %[[SEL]], 1
-    // CHECK-NEXT: ret { i64, i64 } [[REG2]]
+    // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1
+
+    // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0
+    // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0
+    // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1
+
+    // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef
+    // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0
+    // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1
+
+    // CHECK-NEXT: ret { i64, i64 } [[REG3]]
     match x {
         Some(x) => Some(x),
         None => None,
@@ -164,8 +174,8 @@ pub fn control_flow_nop_traits_64(x: ControlFlow<i64, u64>) -> ControlFlow<i64,
 #[no_mangle]
 pub fn result_nop_match_128(x: Result<i128, u128>) -> Result<i128, u128> {
     // CHECK: start:
-    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
     // CHECK-NEXT: store i128
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
     // CHECK-NEXT: store i128
     // CHECK-NEXT: ret void
     match x {
@@ -189,8 +199,8 @@ pub fn result_nop_traits_128(x: Result<i128, u128>) -> Result<i128, u128> {
 #[no_mangle]
 pub fn control_flow_nop_match_128(x: ControlFlow<i128, u128>) -> ControlFlow<i128, u128> {
     // CHECK: start:
-    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
     // CHECK-NEXT: store i128
+    // CHECK-NEXT: getelementptr inbounds {{(nuw )?}}i8
     // CHECK-NEXT: store i128
     // CHECK-NEXT: ret void
     match x {
diff --git a/tests/mir-opt/gvn_clone.rs b/tests/mir-opt/gvn_clone.rs
index c16b665fbd3..08938c0e1b4 100644
--- a/tests/mir-opt/gvn_clone.rs
+++ b/tests/mir-opt/gvn_clone.rs
@@ -1,5 +1,3 @@
-//@ compile-flags: -Zunsound-mir-opts
-// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
 //@ test-mir-pass: GVN
 //@ compile-flags: -Zmir-enable-passes=+InstSimplify-before-inline
 
diff --git a/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff b/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff
index 2a672e82970..0f23415ec53 100644
--- a/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff
+++ b/tests/mir-opt/gvn_clone.{impl#0}-clone.GVN.diff
@@ -1,7 +1,7 @@
-- // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` before GVN
-+ // MIR for `<impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone` after GVN
+- // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` before GVN
++ // MIR for `<impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone` after GVN
   
-  fn <impl at $DIR/gvn_clone.rs:14:10: 14:15>::clone(_1: &AllCopy) -> AllCopy {
+  fn <impl at $DIR/gvn_clone.rs:12:10: 12:15>::clone(_1: &AllCopy) -> AllCopy {
       debug self => _1;
       let mut _0: AllCopy;
       let mut _2: i32;
diff --git a/tests/mir-opt/gvn_copy_aggregate.rs b/tests/mir-opt/gvn_copy_aggregate.rs
index 7c181d1ad37..c9473025a15 100644
--- a/tests/mir-opt/gvn_copy_aggregate.rs
+++ b/tests/mir-opt/gvn_copy_aggregate.rs
@@ -1,5 +1,3 @@
-//@ compile-flags: -Zunsound-mir-opts
-// FIXME: see <https://github.com/rust-lang/rust/issues/132353.
 //@ test-mir-pass: GVN
 //@ compile-flags: -Cpanic=abort
 
diff --git a/tests/mir-opt/pre-codegen/clone_as_copy.rs b/tests/mir-opt/pre-codegen/clone_as_copy.rs
index ae4661e93fd..f5ff1854d38 100644
--- a/tests/mir-opt/pre-codegen/clone_as_copy.rs
+++ b/tests/mir-opt/pre-codegen/clone_as_copy.rs
@@ -1,5 +1,3 @@
-//@ compile-flags: -Zunsound-mir-opts
-// FIXME: see <https://github.com/rust-lang/rust/issues/132353>
 //@ compile-flags: -Cdebuginfo=full
 
 // Check if we have transformed the nested clone to the copy in the complete pipeline.
diff --git a/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir
index 62a9cd9131f..9020cf1ef37 100644
--- a/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/no_inlined_clone.{impl#0}-clone.PreCodegen.after.mir
@@ -3,13 +3,9 @@
 fn <impl at $DIR/no_inlined_clone.rs:9:10: 9:15>::clone(_1: &Foo) -> Foo {
     debug self => _1;
     let mut _0: Foo;
-    let mut _2: i32;
 
     bb0: {
-        StorageLive(_2);
-        _2 = copy ((*_1).0: i32);
-        _0 = Foo { a: move _2 };
-        StorageDead(_2);
+        _0 = copy (*_1);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
index ac485f485b1..889e80d26e1 100644
--- a/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
+++ b/tests/mir-opt/pre-codegen/try_identity.old.PreCodegen.after.mir
@@ -19,14 +19,14 @@ fn old(_1: Result<T, E>) -> Result<T, E> {
     }
 
     bb1: {
-        _3 = move ((_1 as Ok).0: T);
-        _0 = Result::<T, E>::Ok(copy _3);
+        _3 = copy ((_1 as Ok).0: T);
+        _0 = copy _1;
         goto -> bb3;
     }
 
     bb2: {
-        _4 = move ((_1 as Err).0: E);
-        _0 = Result::<T, E>::Err(copy _4);
+        _4 = copy ((_1 as Err).0: E);
+        _0 = copy _1;
         goto -> bb3;
     }
 
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
index 2efc4ef5604..19a00f977eb 100644
--- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
@@ -6,60 +6,52 @@
       let mut _0: std::option::Option<i32>;
       let mut _2: &std::option::Option<i32>;
       let mut _3: &std::option::Option<i32>;
-      let _4: &&mut std::option::Option<i32>;
-      let mut _5: isize;
-      let mut _7: !;
-      let mut _8: std::option::Option<i32>;
-      let mut _9: i32;
-      let mut _10: !;
-      let mut _11: &mut std::option::Option<i32>;
+      let mut _4: isize;
+      let mut _6: !;
+      let mut _7: std::option::Option<i32>;
+      let mut _8: i32;
+      let mut _9: !;
       scope 1 {
-          debug col => _6;
-          let _6: i32;
+          debug col => _5;
+          let _5: i32;
       }
   
       bb0: {
           StorageLive(_2);
           StorageLive(_3);
-          StorageLive(_4);
-          _4 = &_1;
--         _11 = deref_copy (*_4);
--         _3 = &(*_11);
-+         _11 = copy _1;
-+         _3 = &(*_1);
+          _3 = &(*_1);
           _2 = get(move _3) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
           StorageDead(_3);
-          _5 = discriminant((*_2));
-          switchInt(move _5) -> [1: bb2, otherwise: bb3];
+          _4 = discriminant((*_2));
+          switchInt(move _4) -> [1: bb2, otherwise: bb3];
       }
   
       bb2: {
--         StorageLive(_6);
+-         StorageLive(_5);
 +         nop;
-          _6 = copy (((*_2) as Some).0: i32);
-          StorageLive(_8);
--         _8 = Option::<i32>::None;
--         (*_1) = move _8;
-+         _8 = const Option::<i32>::None;
+          _5 = copy (((*_2) as Some).0: i32);
+          StorageLive(_7);
+-         _7 = Option::<i32>::None;
+-         (*_1) = move _7;
++         _7 = const Option::<i32>::None;
 +         (*_1) = const Option::<i32>::None;
+          StorageDead(_7);
+          StorageLive(_8);
+          _8 = copy _5;
+-         _0 = Option::<i32>::Some(move _8);
++         _0 = Option::<i32>::Some(copy _5);
           StorageDead(_8);
-          StorageLive(_9);
-          _9 = copy _6;
--         _0 = Option::<i32>::Some(move _9);
-+         _0 = Option::<i32>::Some(copy _6);
-          StorageDead(_9);
--         StorageDead(_6);
+-         StorageDead(_5);
 +         nop;
-          StorageDead(_4);
           StorageDead(_2);
           return;
       }
   
       bb3: {
-          StorageLive(_10);
+          StorageLive(_9);
           unreachable;
       }
 + }
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
index 47721b768be..87b52ae4808 100644
--- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
@@ -7,8 +7,6 @@
 //! This test demonstrates the behavior, and should be adjusted or removed when fixing and relanding
 //! the mir-opt.
 #![crate_type = "lib"]
-// skip-filecheck
-//@ compile-flags: -O -Zunsound-mir-opts
 //@ test-mir-pass: GVN
 #![allow(internal_features)]
 #![feature(rustc_attrs, core_intrinsics)]
@@ -16,7 +14,15 @@
 // EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
 #[no_mangle]
 fn foo(v: &mut Option<i32>) -> Option<i32> {
-    if let &Some(col) = get(&v) {
+    // CHECK-LABEL: fn foo(
+    // CHECK-SAME: [[v:_.*]]: &mut Option<i32>
+    // CHECK: [[v_alias_1:_.*]] = &(*_1)
+    // CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]])
+    // CHECK: (*[[v]]) = const Option::<i32>::None;
+    // CHECK-NOT: _0 = copy (*[[v_alias_2]])
+    // CHECK: _0 = Option::<i32>::Some
+    // CHECK-NOT: _0 = copy (*[[v_alias_2]])
+    if let &Some(col) = get(v) {
         *v = None;
         return Some(col);
     } else {

From 4e05d858ad602de7d34054016c2277730789dcba Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Mon, 24 Mar 2025 16:55:24 +0800
Subject: [PATCH 8/9] Only preserving derefs for trivial terminators like
 SwitchInt and Goto

---
 compiler/rustc_mir_transform/src/gvn.rs | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index b6294f4ff8a..046f36bdedd 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1779,8 +1779,14 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
                 let opaque = self.new_opaque();
                 self.assign(local, opaque);
             }
-            // Function calls maybe invalidate nested deref, and non-local assignments maybe invalidate deref.
-            // Currently, no distinction is made between these two cases.
+        }
+        // Function calls and ASM may invalidate (nested) derefs. We must handle them carefully.
+        // Currently, only preserving derefs for trivial terminators like SwitchInt and Goto.
+        let safe_to_preserve_derefs = matches!(
+            terminator.kind,
+            TerminatorKind::SwitchInt { .. } | TerminatorKind::Goto { .. }
+        );
+        if !safe_to_preserve_derefs {
             self.invalidate_derefs();
         }
         self.super_terminator(terminator, location);

From 7d44887374ee667bd5aeb5e861032b8ce4093b29 Mon Sep 17 00:00:00 2001
From: dianqk <dianqk@dianqk.net>
Date: Tue, 25 Mar 2025 22:21:18 +0800
Subject: [PATCH 9/9] Invalid dereferences for all non-local mutations

---
 compiler/rustc_mir_transform/src/gvn.rs       | 30 +++++++++--------
 ...mute.undef_union_as_integer.GVN.32bit.diff |  3 +-
 ...mute.undef_union_as_integer.GVN.64bit.diff |  3 +-
 ...in.DestinationPropagation.panic-abort.diff | 10 ++----
 ...n.DestinationPropagation.panic-unwind.diff | 10 ++----
 ..._aggregate_to_copy_miscompile.foo.GVN.diff |  2 +-
 .../simplify_aggregate_to_copy_miscompile.rs  | 33 ++++++++++++++++---
 ..._copy_miscompile.set_discriminant.GVN.diff | 20 +++++++++++
 8 files changed, 75 insertions(+), 36 deletions(-)
 create mode 100644 tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff

diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 046f36bdedd..68bc0ffce6b 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1728,12 +1728,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
         self.tcx
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, location: Location) {
+    fn visit_place(&mut self, place: &mut Place<'tcx>, context: PlaceContext, location: Location) {
         self.simplify_place_projection(place, location);
+        if context.is_mutating_use() && !place.projection.is_empty() {
+            // Non-local mutation maybe invalidate deref.
+            self.invalidate_derefs();
+        }
+        self.super_place(place, context, location);
     }
 
     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) {
         self.simplify_operand(operand, location);
+        self.super_operand(operand, location);
     }
 
     fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, location: Location) {
@@ -1751,22 +1757,18 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
                 self.assign(local, value);
                 Some(value)
             } else {
-                // Non-local assignments maybe invalidate deref.
-                self.invalidate_derefs();
                 value
             };
-            let Some(value) = value else { return };
-
-            if let Some(const_) = self.try_as_constant(value) {
-                *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
-            } else if let Some(local) = self.try_as_local(value, location)
-                && *rvalue != Rvalue::Use(Operand::Move(local.into()))
-            {
-                *rvalue = Rvalue::Use(Operand::Copy(local.into()));
-                self.reused_locals.insert(local);
+            if let Some(value) = value {
+                if let Some(const_) = self.try_as_constant(value) {
+                    *rvalue = Rvalue::Use(Operand::Constant(Box::new(const_)));
+                } else if let Some(local) = self.try_as_local(value, location)
+                    && *rvalue != Rvalue::Use(Operand::Move(local.into()))
+                {
+                    *rvalue = Rvalue::Use(Operand::Copy(local.into()));
+                    self.reused_locals.insert(local);
+                }
             }
-
-            return;
         }
         self.super_statement(stmt, location);
     }
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
index febb6bfb0a4..2ac9769a0e7 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.32bit.diff
@@ -10,8 +10,9 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = ();
+-         _1 = Union32 { value: move _2 };
 +         _2 = const ();
-          _1 = Union32 { value: move _2 };
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
index febb6bfb0a4..2ac9769a0e7 100644
--- a/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
+++ b/tests/mir-opt/const_prop/transmute.undef_union_as_integer.GVN.64bit.diff
@@ -10,8 +10,9 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = ();
+-         _1 = Union32 { value: move _2 };
 +         _2 = const ();
-          _1 = Union32 { value: move _2 };
++         _1 = Union32 { value: const () };
           StorageDead(_2);
           _0 = move _1 as u32 (Transmute);
           StorageDead(_1);
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
index 557320f0179..ef418798faa 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-abort.diff
@@ -5,11 +5,10 @@
       let mut _0: ();
       let _1: main::Un;
       let mut _2: u32;
-      let mut _3: u32;
       scope 1 {
           debug un => _1;
           scope 3 (inlined std::mem::drop::<u32>) {
-              debug _x => _3;
+              debug _x => _2;
           }
       }
       scope 2 (inlined val) {
@@ -17,13 +16,10 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
-          nop;
           _1 = Un { us: const 1_u32 };
+          StorageLive(_2);
+          _2 = copy (_1.0: u32);
           StorageDead(_2);
-          StorageLive(_3);
-          _3 = copy (_1.0: u32);
-          StorageDead(_3);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
index 557320f0179..ef418798faa 100644
--- a/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
+++ b/tests/mir-opt/dest-prop/union.main.DestinationPropagation.panic-unwind.diff
@@ -5,11 +5,10 @@
       let mut _0: ();
       let _1: main::Un;
       let mut _2: u32;
-      let mut _3: u32;
       scope 1 {
           debug un => _1;
           scope 3 (inlined std::mem::drop::<u32>) {
-              debug _x => _3;
+              debug _x => _2;
           }
       }
       scope 2 (inlined val) {
@@ -17,13 +16,10 @@
   
       bb0: {
           StorageLive(_1);
-          StorageLive(_2);
-          nop;
           _1 = Un { us: const 1_u32 };
+          StorageLive(_2);
+          _2 = copy (_1.0: u32);
           StorageDead(_2);
-          StorageLive(_3);
-          _3 = copy (_1.0: u32);
-          StorageDead(_3);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
index 19a00f977eb..54c11679f0c 100644
--- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.foo.GVN.diff
@@ -20,7 +20,7 @@
           StorageLive(_2);
           StorageLive(_3);
           _3 = &(*_1);
-          _2 = get(move _3) -> [return: bb1, unwind unreachable];
+          _2 = get::<Option<i32>>(move _3) -> [return: bb1, unwind unreachable];
       }
   
       bb1: {
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
index 87b52ae4808..33e31b56977 100644
--- a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.rs
@@ -9,15 +9,16 @@
 #![crate_type = "lib"]
 //@ test-mir-pass: GVN
 #![allow(internal_features)]
-#![feature(rustc_attrs, core_intrinsics)]
+#![feature(core_intrinsics, custom_mir, rustc_attrs)]
+
+use std::intrinsics::mir::*;
 
 // EMIT_MIR simplify_aggregate_to_copy_miscompile.foo.GVN.diff
-#[no_mangle]
 fn foo(v: &mut Option<i32>) -> Option<i32> {
     // CHECK-LABEL: fn foo(
     // CHECK-SAME: [[v:_.*]]: &mut Option<i32>
     // CHECK: [[v_alias_1:_.*]] = &(*_1)
-    // CHECK-NEXT: [[v_alias_2:_.*]] = get(move [[v_alias_1]])
+    // CHECK-NEXT: [[v_alias_2:_.*]] = get::<Option<i32>>(move [[v_alias_1]])
     // CHECK: (*[[v]]) = const Option::<i32>::None;
     // CHECK-NOT: _0 = copy (*[[v_alias_2]])
     // CHECK: _0 = Option::<i32>::Some
@@ -30,9 +31,31 @@ fn foo(v: &mut Option<i32>) -> Option<i32> {
     }
 }
 
-#[no_mangle]
+pub enum Value {
+    V0(i32),
+    V1(i32),
+}
+
+// EMIT_MIR simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
+#[custom_mir(dialect = "runtime", phase = "initial")]
+fn set_discriminant(v: &mut Value) -> Value {
+    // CHECK-LABEL: fn set_discriminant(
+    mir! {
+        let v_: &Value;
+        {
+            Call(v_ = get(v), ReturnTo(ret), UnwindUnreachable())
+        }
+        ret = {
+            let col: i32 = Field(Variant(*v_, 0), 0);
+            SetDiscriminant(*v, 1);
+            RET = Value::V0(col);
+            Return()
+        }
+    }
+}
+
 #[inline(never)]
 #[rustc_nounwind]
-fn get(v: &Option<i32>) -> &Option<i32> {
+fn get<T>(v: &T) -> &T {
     v
 }
diff --git a/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
new file mode 100644
index 00000000000..41f9763d024
--- /dev/null
+++ b/tests/mir-opt/simplify_aggregate_to_copy_miscompile.set_discriminant.GVN.diff
@@ -0,0 +1,20 @@
+- // MIR for `set_discriminant` before GVN
++ // MIR for `set_discriminant` after GVN
+  
+  fn set_discriminant(_1: &mut Value) -> Value {
+      let mut _0: Value;
+      let mut _2: &Value;
+      let mut _3: i32;
+  
+      bb0: {
+          _2 = get::<Value>(copy _1) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          _3 = copy (((*_2) as variant#0).0: i32);
+          discriminant((*_1)) = 1;
+          _0 = Value::V0(copy _3);
+          return;
+      }
+  }
+