about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-03 21:50:13 +0000
committerbors <bors@rust-lang.org>2024-05-03 21:50:13 +0000
commitd2d24e395a1e4fcee62ca17bf4cbddb1f903af97 (patch)
tree80f6cdd1827141815396f9aa6459ab018a8af9e1
parentbefabbc9e5f6e82e659f9f52040ee0dd40593d8a (diff)
parentc19866f335152cbdd3424b573e5a615963dbe80e (diff)
downloadrust-d2d24e395a1e4fcee62ca17bf4cbddb1f903af97.tar.gz
rust-d2d24e395a1e4fcee62ca17bf4cbddb1f903af97.zip
Auto merge of #123602 - cjgillot:gvn-borrowed, r=oli-obk
Account for immutably borrowed locals in MIR copy-prop and GVN

For the most part, we consider that immutably borrowed `Freeze` locals still fulfill SSA conditions. As the borrow is immutable, any use of the local will have the value given by the single assignment, and there can be no surprise.

This allows copy-prop to merge a non-borrowed local with a borrowed local. We chose to keep copy-classes heads unborrowed, as those may be easier to optimize in later passes.

This also allows to GVN the value behind an immutable borrow. If a SSA local is borrowed, dereferencing that borrow is equivalent to copying the local's value: re-executing the assignment between the borrow and the dereference would be UB.

r? `@ghost` for perf
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs41
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs18
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs3
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs55
-rw-r--r--tests/coverage/issue-83601.cov-map6
-rw-r--r--tests/coverage/issue-84561.cov-map22
-rw-r--r--tests/crashes/111883.rs40
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff24
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff24
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-abort.diff (renamed from tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-abort.diff)6
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-unwind.diff (renamed from tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff)6
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-abort.diff23
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-unwind.diff23
-rw-r--r--tests/mir-opt/copy-prop/borrowed_local.rs71
-rw-r--r--tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff29
-rw-r--r--tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff29
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff18
-rw-r--r--tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff18
-rw-r--r--tests/mir-opt/gvn.non_freeze.GVN.panic-abort.diff27
-rw-r--r--tests/mir-opt/gvn.non_freeze.GVN.panic-unwind.diff27
-rw-r--r--tests/mir-opt/gvn.rs65
-rw-r--r--tests/mir-opt/gvn.slices.GVN.panic-abort.diff38
-rw-r--r--tests/mir-opt/gvn.slices.GVN.panic-unwind.diff38
-rw-r--r--tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff3
-rw-r--r--tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff3
-rw-r--r--tests/mir-opt/pre-codegen/slice_filter.variant_a-{closure#0}.PreCodegen.after.mir211
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff6
-rw-r--r--tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff6
-rw-r--r--tests/mir-opt/reference_prop.rs10
30 files changed, 591 insertions, 302 deletions
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index 0119b95cced..c1f9313a377 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -3,7 +3,6 @@ use rustc_index::IndexSlice;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
-use rustc_mir_dataflow::impls::borrowed_locals;
 
 use crate::ssa::SsaLocals;
 
@@ -32,8 +31,8 @@ impl<'tcx> MirPass<'tcx> for CopyProp {
 }
 
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let borrowed_locals = borrowed_locals(body);
-    let ssa = SsaLocals::new(body);
+    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+    let ssa = SsaLocals::new(tcx, body, param_env);
 
     let fully_moved = fully_moved_locals(&ssa, body);
     debug!(?fully_moved);
@@ -51,7 +50,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
         tcx,
         copy_classes: ssa.copy_classes(),
         fully_moved,
-        borrowed_locals,
+        borrowed_locals: ssa.borrowed_locals(),
         storage_to_remove,
     }
     .visit_body_preserves_cfg(body);
@@ -101,7 +100,7 @@ struct Replacer<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     fully_moved: BitSet<Local>,
     storage_to_remove: BitSet<Local>,
-    borrowed_locals: BitSet<Local>,
+    borrowed_locals: &'a BitSet<Local>,
     copy_classes: &'a IndexSlice<Local, Local>,
 }
 
@@ -112,6 +111,12 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
 
     fn visit_local(&mut self, local: &mut Local, ctxt: PlaceContext, _: Location) {
         let new_local = self.copy_classes[*local];
+        // We must not unify two locals that are borrowed. But this is fine if one is borrowed and
+        // the other is not. We chose to check the original local, and not the target. That way, if
+        // the original local is borrowed and the target is not, we do not pessimize the whole class.
+        if self.borrowed_locals.contains(*local) {
+            return;
+        }
         match ctxt {
             // Do not modify the local in storage statements.
             PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead) => {}
@@ -122,32 +127,14 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
         }
     }
 
-    fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+    fn visit_place(&mut self, place: &mut Place<'tcx>, _: PlaceContext, loc: Location) {
         if let Some(new_projection) = self.process_projection(place.projection, loc) {
             place.projection = self.tcx().mk_place_elems(&new_projection);
         }
 
-        let observes_address = match ctxt {
-            PlaceContext::NonMutatingUse(
-                NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::FakeBorrow
-                | NonMutatingUseContext::AddressOf,
-            ) => true,
-            // For debuginfo, merging locals is ok.
-            PlaceContext::NonUse(NonUseContext::VarDebugInfo) => {
-                self.borrowed_locals.contains(place.local)
-            }
-            _ => false,
-        };
-        if observes_address && !place.is_indirect() {
-            // We observe the address of `place.local`. Do not replace it.
-        } else {
-            self.visit_local(
-                &mut place.local,
-                PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
-                loc,
-            )
-        }
+        // Any non-mutating use context is ok.
+        let ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
+        self.visit_local(&mut place.local, ctxt, loc)
     }
 
     fn visit_operand(&mut self, operand: &mut Operand<'tcx>, loc: Location) {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 24832086b16..4dd595ce1e1 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -121,7 +121,7 @@ impl<'tcx> MirPass<'tcx> for GVN {
 
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
     let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
-    let ssa = SsaLocals::new(body);
+    let ssa = SsaLocals::new(tcx, body, param_env);
     // Clone dominators as we need them while mutating the body.
     let dominators = body.basic_blocks.dominators().clone();
 
@@ -724,6 +724,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         // Invariant: `value` holds the value up-to the `index`th projection excluded.
         let mut value = self.locals[place.local]?;
         for (index, proj) in place.projection.iter().enumerate() {
+            if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
+                && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
+                && let AddressKind::Ref(BorrowKind::Shared) = kind
+                && let Some(v) = self.simplify_place_value(&mut pointee, location)
+            {
+                value = v;
+                place_ref = pointee.project_deeper(&place.projection[index..], self.tcx).as_ref();
+            }
             if let Some(local) = self.try_as_local(value, location) {
                 // Both `local` and `Place { local: place.local, projection: projection[..index] }`
                 // hold the same value. Therefore, following place holds the value in the original
@@ -735,6 +743,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             value = self.project(base, value, proj)?;
         }
 
+        if let Value::Projection(pointer, ProjectionElem::Deref) = *self.get(value)
+            && let Value::Address { place: mut pointee, kind, .. } = *self.get(pointer)
+            && let AddressKind::Ref(BorrowKind::Shared) = kind
+            && let Some(v) = self.simplify_place_value(&mut pointee, location)
+        {
+            value = v;
+            place_ref = pointee.project_deeper(&[], self.tcx).as_ref();
+        }
         if let Some(new_local) = self.try_as_local(value, location) {
             place_ref = PlaceRef { local: new_local, projection: &[] };
         }
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index 128634bd7f2..c26a5461633 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -22,7 +22,8 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
 }
 
 fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
-    let ssa = SsaLocals::new(body);
+    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+    let ssa = SsaLocals::new(tcx, body, param_env);
 
     let slice_lengths = compute_slice_length(tcx, &ssa, body);
     debug!(?slice_lengths);
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index d5642be5513..044ae32c1d4 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -82,7 +82,8 @@ impl<'tcx> MirPass<'tcx> for ReferencePropagation {
 }
 
 fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
-    let ssa = SsaLocals::new(body);
+    let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
+    let ssa = SsaLocals::new(tcx, body, param_env);
 
     let mut replacer = compute_replacement(tcx, body, &ssa);
     debug!(?replacer.targets);
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index fddc62e6652..55fed7d9da2 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -2,8 +2,9 @@
 //! 1/ They are only assigned-to once, either as a function parameter, or in an assign statement;
 //! 2/ This single assignment dominates all uses;
 //!
-//! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
-//! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
+//! As we do not track indirect assignments, a local that has its address taken (either by
+//! AddressOf or by borrowing) is considered non-SSA. However, it is UB to modify through an
+//! immutable borrow of a `Freeze` local. Those can still be considered to be SSA.
 
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
@@ -11,6 +12,7 @@ use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
+use rustc_middle::ty::{ParamEnv, TyCtxt};
 
 pub struct SsaLocals {
     /// Assignments to each local. This defines whether the local is SSA.
@@ -24,6 +26,8 @@ pub struct SsaLocals {
     /// Number of "direct" uses of each local, ie. uses that are not dereferences.
     /// We ignore non-uses (Storage statements, debuginfo).
     direct_uses: IndexVec<Local, u32>,
+    /// Set of SSA locals that are immutably borrowed.
+    borrowed_locals: BitSet<Local>,
 }
 
 pub enum AssignedValue<'a, 'tcx> {
@@ -33,15 +37,22 @@ pub enum AssignedValue<'a, 'tcx> {
 }
 
 impl SsaLocals {
-    pub fn new<'tcx>(body: &Body<'tcx>) -> SsaLocals {
+    pub fn new<'tcx>(tcx: TyCtxt<'tcx>, body: &Body<'tcx>, param_env: ParamEnv<'tcx>) -> SsaLocals {
         let assignment_order = Vec::with_capacity(body.local_decls.len());
 
         let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
         let dominators = body.basic_blocks.dominators();
 
         let direct_uses = IndexVec::from_elem(0, &body.local_decls);
-        let mut visitor =
-            SsaVisitor { body, assignments, assignment_order, dominators, direct_uses };
+        let borrowed_locals = BitSet::new_empty(body.local_decls.len());
+        let mut visitor = SsaVisitor {
+            body,
+            assignments,
+            assignment_order,
+            dominators,
+            direct_uses,
+            borrowed_locals,
+        };
 
         for local in body.args_iter() {
             visitor.assignments[local] = Set1::One(DefLocation::Argument);
@@ -58,6 +69,16 @@ impl SsaLocals {
             visitor.visit_var_debug_info(var_debug_info);
         }
 
+        // The immutability of shared borrows only works on `Freeze` locals. If the visitor found
+        // borrows, we need to check the types. For raw pointers and mutable borrows, the locals
+        // have already been marked as non-SSA.
+        debug!(?visitor.borrowed_locals);
+        for local in visitor.borrowed_locals.iter() {
+            if !body.local_decls[local].ty.is_freeze(tcx, param_env) {
+                visitor.assignments[local] = Set1::Many;
+            }
+        }
+
         debug!(?visitor.assignments);
         debug!(?visitor.direct_uses);
 
@@ -70,6 +91,7 @@ impl SsaLocals {
             assignments: visitor.assignments,
             assignment_order: visitor.assignment_order,
             direct_uses: visitor.direct_uses,
+            borrowed_locals: visitor.borrowed_locals,
             // This is filled by `compute_copy_classes`.
             copy_classes: IndexVec::default(),
         };
@@ -174,6 +196,11 @@ impl SsaLocals {
         &self.copy_classes
     }
 
+    /// Set of SSA locals that are immutably borrowed.
+    pub fn borrowed_locals(&self) -> &BitSet<Local> {
+        &self.borrowed_locals
+    }
+
     /// Make a property uniform on a copy equivalence class by removing elements.
     pub fn meet_copy_equivalence(&self, property: &mut BitSet<Local>) {
         // Consolidate to have a local iff all its copies are.
@@ -208,6 +235,8 @@ struct SsaVisitor<'tcx, 'a> {
     assignments: IndexVec<Local, Set1<DefLocation>>,
     assignment_order: Vec<Local>,
     direct_uses: IndexVec<Local, u32>,
+    // Track locals that are immutably borrowed, so we can check their type is `Freeze` later.
+    borrowed_locals: BitSet<Local>,
 }
 
 impl SsaVisitor<'_, '_> {
@@ -232,16 +261,18 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor<'tcx, '_> {
             PlaceContext::MutatingUse(MutatingUseContext::Projection)
             | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(),
             // Anything can happen with raw pointers, so remove them.
-            // We do not verify that all uses of the borrow dominate the assignment to `local`,
-            // so we have to remove them too.
-            PlaceContext::NonMutatingUse(
-                NonMutatingUseContext::SharedBorrow
-                | NonMutatingUseContext::FakeBorrow
-                | NonMutatingUseContext::AddressOf,
-            )
+            PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
             | PlaceContext::MutatingUse(_) => {
                 self.assignments[local] = Set1::Many;
             }
+            // Immutable borrows are ok, but we need to delay a check that the type is `Freeze`.
+            PlaceContext::NonMutatingUse(
+                NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::FakeBorrow,
+            ) => {
+                self.borrowed_locals.insert(local);
+                self.check_dominates(local, loc);
+                self.direct_uses[local] += 1;
+            }
             PlaceContext::NonMutatingUse(_) => {
                 self.check_dominates(local, loc);
                 self.direct_uses[local] += 1;
diff --git a/tests/coverage/issue-83601.cov-map b/tests/coverage/issue-83601.cov-map
index f2447e3c92c..ddb4407881a 100644
--- a/tests/coverage/issue-83601.cov-map
+++ b/tests/coverage/issue-83601.cov-map
@@ -1,12 +1,12 @@
 Function name: issue_83601::main
-Raw bytes (21): 0x[01, 01, 01, 05, 09, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
+Raw bytes (21): 0x[01, 01, 01, 05, 00, 03, 01, 06, 01, 02, 1c, 05, 03, 09, 01, 1c, 02, 02, 05, 03, 02]
 Number of files: 1
 - file 0 => global file 1
 Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(1), rhs = Zero
 Number of file 0 mappings: 3
 - Code(Counter(0)) at (prev + 6, 1) to (start + 2, 28)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 1, 28)
 - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 3, 2)
-    = (c1 - c2)
+    = (c1 - Zero)
 
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index a81884ea942..ab66a2fffce 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -77,22 +77,22 @@ Number of file 0 mappings: 1
 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10)
 
 Function name: issue_84561::test3
-Raw bytes (436): 0x[01, 01, 41, 05, 09, 0d, 00, 15, 19, 12, 00, 15, 19, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 41, 2e, 45, 3d, 41, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
+Raw bytes (436): 0x[01, 01, 41, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 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: 65
-- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 0 operands: lhs = Counter(1), rhs = Zero
 - expression 1 operands: lhs = Counter(3), rhs = Zero
-- expression 2 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 2 operands: lhs = Counter(5), rhs = Zero
 - expression 3 operands: lhs = Expression(4, Sub), rhs = Zero
-- expression 4 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(5), rhs = Zero
 - expression 5 operands: lhs = Counter(8), rhs = Zero
 - expression 6 operands: lhs = Expression(7, Sub), rhs = Zero
 - expression 7 operands: lhs = Counter(8), rhs = Zero
 - expression 8 operands: lhs = Counter(12), rhs = Zero
-- expression 9 operands: lhs = Counter(15), rhs = Counter(16)
+- expression 9 operands: lhs = Counter(15), rhs = Zero
 - expression 10 operands: lhs = Expression(11, Sub), rhs = Counter(17)
-- expression 11 operands: lhs = Counter(15), rhs = Counter(16)
+- expression 11 operands: lhs = Counter(15), rhs = Zero
 - expression 12 operands: lhs = Expression(16, Sub), rhs = Counter(18)
 - expression 13 operands: lhs = Counter(17), rhs = Zero
 - expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20)
@@ -150,15 +150,15 @@ Number of file 0 mappings: 51
 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28)
 - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28)
 - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 4, 31)
-    = (c1 - c2)
+    = (c1 - Zero)
 - Code(Counter(3)) at (prev + 5, 5) to (start + 0, 31)
 - Code(Expression(1, Sub)) at (prev + 1, 5) to (start + 0, 31)
     = (c3 - Zero)
 - Code(Counter(5)) at (prev + 1, 9) to (start + 1, 28)
 - Code(Expression(4, Sub)) at (prev + 2, 5) to (start + 0, 31)
-    = (c5 - c6)
+    = (c5 - Zero)
 - Code(Expression(3, Sub)) at (prev + 1, 5) to (start + 0, 15)
-    = ((c5 - c6) - Zero)
+    = ((c5 - Zero) - Zero)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 48)
 - Code(Counter(8)) at (prev + 1, 5) to (start + 3, 15)
 - Code(Zero) at (prev + 3, 32) to (start + 0, 48)
@@ -176,10 +176,10 @@ Number of file 0 mappings: 51
     = (c12 - Zero)
 - Code(Counter(15)) at (prev + 4, 9) to (start + 4, 6)
 - Code(Expression(11, Sub)) at (prev + 5, 8) to (start + 0, 15)
-    = (c15 - c16)
+    = (c15 - Zero)
 - Code(Counter(17)) at (prev + 1, 9) to (start + 3, 10)
 - Code(Expression(10, Sub)) at (prev + 5, 9) to (start + 3, 10)
-    = ((c15 - c16) - c17)
+    = ((c15 - Zero) - c17)
 - Code(Expression(15, Add)) at (prev + 5, 8) to (start + 0, 15)
     = ((c17 - Zero) + c18)
 - Code(Counter(20)) at (prev + 1, 9) to (start + 0, 19)
diff --git a/tests/crashes/111883.rs b/tests/crashes/111883.rs
deleted file mode 100644
index fa72b28c228..00000000000
--- a/tests/crashes/111883.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-//@ known-bug: #111883
-#![crate_type = "lib"]
-#![feature(arbitrary_self_types, no_core, lang_items)]
-#![no_core]
-
-#[lang = "sized"]
-trait Sized {}
-#[lang = "copy"]
-trait Copy {}
-#[lang = "receiver"]
-trait Receiver {}
-#[lang = "dispatch_from_dyn"]
-trait DispatchFromDyn<T> {}
-impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
-#[lang = "unsize"]
-trait Unsize<T: ?Sized> {}
-#[lang = "coerce_unsized"]
-pub trait CoerceUnsized<T: ?Sized> {}
-impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
-
-#[lang = "drop_in_place"]
-fn drop_in_place_fn<T>(a: &dyn Trait2<T>) {}
-
-pub trait Trait1 {
-    fn foo(&self);
-}
-
-pub struct Type1;
-
-impl Trait1 for Type1 {
-    fn foo(&self) {}
-}
-
-pub trait Trait2<T> {}
-
-pub fn bar1() {
-    let a = Type1;
-    let b = &a as &dyn Trait1;
-    b.foo();
-}
diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff
new file mode 100644
index 00000000000..897592a0e2f
--- /dev/null
+++ b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-abort.diff
@@ -0,0 +1,24 @@
+- // MIR for `borrowed` before CopyProp
++ // MIR for `borrowed` after CopyProp
+  
+  fn borrowed(_1: T) -> bool {
+      let mut _0: bool;
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+-         _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
++         _0 = opaque::<T>(_1) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff
new file mode 100644
index 00000000000..33c05af91a1
--- /dev/null
+++ b/tests/mir-opt/copy-prop/borrowed_local.borrowed.CopyProp.panic-unwind.diff
@@ -0,0 +1,24 @@
+- // MIR for `borrowed` before CopyProp
++ // MIR for `borrowed` after CopyProp
+  
+  fn borrowed(_1: T) -> bool {
+      let mut _0: bool;
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+-         _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
++         _0 = opaque::<T>(_1) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-abort.diff
index 46534076c29..3d6b5dffba4 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-abort.diff
+++ b/tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-abort.diff
@@ -1,7 +1,7 @@
-- // MIR for `f` before CopyProp
-+ // MIR for `f` after CopyProp
+- // MIR for `compare_address` before CopyProp
++ // MIR for `compare_address` after CopyProp
   
-  fn f() -> bool {
+  fn compare_address() -> bool {
       let mut _0: bool;
       let mut _1: u8;
       let mut _2: &u8;
diff --git a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-unwind.diff
index b702e3b7d1e..0f29d2681de 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.f.CopyProp.panic-unwind.diff
+++ b/tests/mir-opt/copy-prop/borrowed_local.compare_address.CopyProp.panic-unwind.diff
@@ -1,7 +1,7 @@
-- // MIR for `f` before CopyProp
-+ // MIR for `f` after CopyProp
+- // MIR for `compare_address` before CopyProp
++ // MIR for `compare_address` after CopyProp
   
-  fn f() -> bool {
+  fn compare_address() -> bool {
       let mut _0: bool;
       let mut _1: u8;
       let mut _2: &u8;
diff --git a/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-abort.diff b/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-abort.diff
new file mode 100644
index 00000000000..af2aeb0dcab
--- /dev/null
+++ b/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-abort.diff
@@ -0,0 +1,23 @@
+- // MIR for `non_freeze` before CopyProp
++ // MIR for `non_freeze` after CopyProp
+  
+  fn non_freeze(_1: T) -> bool {
+      let mut _0: bool;
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-unwind.diff b/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-unwind.diff
new file mode 100644
index 00000000000..040ed0aec16
--- /dev/null
+++ b/tests/mir-opt/copy-prop/borrowed_local.non_freeze.CopyProp.panic-unwind.diff
@@ -0,0 +1,23 @@
+- // MIR for `non_freeze` before CopyProp
++ // MIR for `non_freeze` after CopyProp
+  
+  fn non_freeze(_1: T) -> bool {
+      let mut _0: bool;
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/copy-prop/borrowed_local.rs b/tests/mir-opt/copy-prop/borrowed_local.rs
index 74ac6281a89..512287dd176 100644
--- a/tests/mir-opt/copy-prop/borrowed_local.rs
+++ b/tests/mir-opt/copy-prop/borrowed_local.rs
@@ -1,10 +1,10 @@
-// skip-filecheck
 // EMIT_MIR_FOR_EACH_PANIC_STRATEGY
 //@ test-mir-pass: CopyProp
 
-#![feature(custom_mir, core_intrinsics)]
+#![feature(custom_mir, core_intrinsics, freeze)]
 #![allow(unused_assignments)]
 extern crate core;
+use core::marker::Freeze;
 use core::intrinsics::mir::*;
 
 fn opaque(_: impl Sized) -> bool { true }
@@ -14,7 +14,16 @@ fn cmp_ref(a: &u8, b: &u8) -> bool {
 }
 
 #[custom_mir(dialect = "analysis", phase = "post-cleanup")]
-fn f() -> bool {
+fn compare_address() -> bool {
+    // CHECK-LABEL: fn compare_address(
+    // CHECK: bb0: {
+    // CHECK-NEXT: _1 = const 5_u8;
+    // CHECK-NEXT: _2 = &_1;
+    // CHECK-NEXT: _3 = _1;
+    // CHECK-NEXT: _4 = &_3;
+    // CHECK-NEXT: _0 = cmp_ref(_2, _4)
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = opaque::<u8>(_3)
     mir!(
         {
             let a = 5_u8;
@@ -34,8 +43,60 @@ fn f() -> bool {
     )
 }
 
+/// Generic type `T` is `Freeze`, so shared borrows are immutable.
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn borrowed<T: Copy + Freeze>(x: T) -> bool {
+    // CHECK-LABEL: fn borrowed(
+    // CHECK: bb0: {
+    // CHECK-NEXT: _3 = &_1;
+    // CHECK-NEXT: _0 = opaque::<&T>(_3)
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = opaque::<T>(_1)
+    mir!(
+        {
+            let a = x;
+            let r1 = &x;
+            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
+        }
+        next = {
+            Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn non_freeze<T: Copy>(x: T) -> bool {
+    // CHECK-LABEL: fn non_freeze(
+    // CHECK: bb0: {
+    // CHECK-NEXT: _2 = _1;
+    // CHECK-NEXT: _3 = &_1;
+    // CHECK-NEXT: _0 = opaque::<&T>(_3)
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = opaque::<T>(_2)
+    mir!(
+        {
+            let a = x;
+            let r1 = &x;
+            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
+        }
+        next = {
+            Call(RET = opaque(a), ReturnTo(ret), UnwindContinue())
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
 fn main() {
-    assert!(!f());
+    assert!(!compare_address());
+    non_freeze(5);
 }
 
-// EMIT_MIR borrowed_local.f.CopyProp.diff
+// EMIT_MIR borrowed_local.compare_address.CopyProp.diff
+// EMIT_MIR borrowed_local.borrowed.CopyProp.diff
+// EMIT_MIR borrowed_local.non_freeze.CopyProp.diff
diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff
new file mode 100644
index 00000000000..9520bd382ee
--- /dev/null
+++ b/tests/mir-opt/gvn.borrowed.GVN.panic-abort.diff
@@ -0,0 +1,29 @@
+- // MIR for `borrowed` before GVN
++ // MIR for `borrowed` after GVN
+  
+  fn borrowed(_1: T) -> () {
+      let mut _0: ();
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+-         _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
++         _0 = opaque::<T>(_1) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+-         _0 = opaque::<T>((*_3)) -> [return: bb3, unwind unreachable];
++         _0 = opaque::<T>(_1) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..4f5d76d5644
--- /dev/null
+++ b/tests/mir-opt/gvn.borrowed.GVN.panic-unwind.diff
@@ -0,0 +1,29 @@
+- // MIR for `borrowed` before GVN
++ // MIR for `borrowed` after GVN
+  
+  fn borrowed(_1: T) -> () {
+      let mut _0: ();
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+-         _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
++         _0 = opaque::<T>(_1) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+-         _0 = opaque::<T>((*_3)) -> [return: bb3, unwind continue];
++         _0 = opaque::<T>(_1) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
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 02bf95840da..68cb4d55e7b 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:610:19: 610:21};
+      let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
+      let mut _13: {closure@$DIR/gvn.rs:612:19: 612: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:610:19: 610:21};
+              let _7: {closure@$DIR/gvn.rs:612:19: 612:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
+-         _7 = {closure@$DIR/gvn.rs:612:19: 612:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           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 c5dcc8a8ec9..fa184348b3b 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:610:19: 610:21};
+      let mut _9: {closure@$DIR/gvn.rs:612:19: 612:21};
       let _10: ();
       let mut _11: fn();
-      let mut _13: {closure@$DIR/gvn.rs:610:19: 610:21};
+      let mut _13: {closure@$DIR/gvn.rs:612:19: 612: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:610:19: 610:21};
+              let _7: {closure@$DIR/gvn.rs:612:19: 612:21};
               scope 3 {
                   debug closure => _7;
                   let _8: fn();
@@ -62,16 +62,16 @@
           StorageDead(_6);
           StorageDead(_5);
 -         StorageLive(_7);
--         _7 = {closure@$DIR/gvn.rs:610:19: 610:21};
+-         _7 = {closure@$DIR/gvn.rs:612:19: 612:21};
 -         StorageLive(_8);
 +         nop;
-+         _7 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
++         _7 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
 -         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _9 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -88,8 +88,8 @@
           StorageLive(_13);
 -         _13 = _7;
 -         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
-+         _13 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:610:19: 610:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.non_freeze.GVN.panic-abort.diff b/tests/mir-opt/gvn.non_freeze.GVN.panic-abort.diff
new file mode 100644
index 00000000000..7b6ed096118
--- /dev/null
+++ b/tests/mir-opt/gvn.non_freeze.GVN.panic-abort.diff
@@ -0,0 +1,27 @@
+- // MIR for `non_freeze` before GVN
++ // MIR for `non_freeze` after GVN
+  
+  fn non_freeze(_1: T) -> () {
+      let mut _0: ();
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          _0 = opaque::<T>(_2) -> [return: bb2, unwind unreachable];
+      }
+  
+      bb2: {
+          _0 = opaque::<T>((*_3)) -> [return: bb3, unwind unreachable];
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.non_freeze.GVN.panic-unwind.diff b/tests/mir-opt/gvn.non_freeze.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..641a2f4609a
--- /dev/null
+++ b/tests/mir-opt/gvn.non_freeze.GVN.panic-unwind.diff
@@ -0,0 +1,27 @@
+- // MIR for `non_freeze` before GVN
++ // MIR for `non_freeze` after GVN
+  
+  fn non_freeze(_1: T) -> () {
+      let mut _0: ();
+      let mut _2: T;
+      let mut _3: &T;
+  
+      bb0: {
+          _2 = _1;
+          _3 = &_1;
+          _0 = opaque::<&T>(_3) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          _0 = opaque::<T>(_2) -> [return: bb2, unwind continue];
+      }
+  
+      bb2: {
+          _0 = opaque::<T>((*_3)) -> [return: bb3, unwind continue];
+      }
+  
+      bb3: {
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 0484710f00e..9be30515283 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -6,9 +6,11 @@
 #![feature(rustc_attrs)]
 #![feature(custom_mir)]
 #![feature(core_intrinsics)]
+#![feature(freeze)]
 #![allow(unconditional_panic)]
 
 use std::intrinsics::mir::*;
+use std::marker::Freeze;
 use std::mem::transmute;
 
 struct S<T>(T);
@@ -720,6 +722,65 @@ fn wide_ptr_integer() {
     opaque(a >= b);
 }
 
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn borrowed<T: Copy + Freeze>(x: T) {
+    // CHECK-LABEL: fn borrowed(
+    // CHECK: bb0: {
+    // CHECK-NEXT: _2 = _1;
+    // CHECK-NEXT: _3 = &_1;
+    // CHECK-NEXT: _0 = opaque::<&T>(_3)
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = opaque::<T>(_1)
+    // CHECK: bb2: {
+    // CHECK-NEXT: _0 = opaque::<T>(_1)
+    mir!(
+        {
+            let a = x;
+            let r1 = &x;
+            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
+        }
+        next = {
+            Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
+        }
+        deref = {
+            Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
+/// Generic type `T` is not known to be `Freeze`, so shared borrows may be mutable.
+#[custom_mir(dialect = "analysis", phase = "post-cleanup")]
+fn non_freeze<T: Copy>(x: T) {
+    // CHECK-LABEL: fn non_freeze(
+    // CHECK: bb0: {
+    // CHECK-NEXT: _2 = _1;
+    // CHECK-NEXT: _3 = &_1;
+    // CHECK-NEXT: _0 = opaque::<&T>(_3)
+    // CHECK: bb1: {
+    // CHECK-NEXT: _0 = opaque::<T>(_2)
+    // CHECK: bb2: {
+    // CHECK-NEXT: _0 = opaque::<T>((*_3))
+    mir!(
+        {
+            let a = x;
+            let r1 = &x;
+            Call(RET = opaque(r1), ReturnTo(next), UnwindContinue())
+        }
+        next = {
+            Call(RET = opaque(a), ReturnTo(deref), UnwindContinue())
+        }
+        deref = {
+            Call(RET = opaque(*r1), ReturnTo(ret), UnwindContinue())
+        }
+        ret = {
+            Return()
+        }
+    )
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
@@ -742,6 +803,8 @@ fn main() {
     constant_index_overflow(&[5, 3]);
     wide_ptr_provenance();
     wide_ptr_integer();
+    borrowed(5);
+    non_freeze(5);
 }
 
 #[inline(never)]
@@ -773,3 +836,5 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.wide_ptr_provenance.GVN.diff
 // EMIT_MIR gvn.wide_ptr_same_provenance.GVN.diff
 // EMIT_MIR gvn.wide_ptr_integer.GVN.diff
+// EMIT_MIR gvn.borrowed.GVN.diff
+// EMIT_MIR gvn.non_freeze.GVN.diff
diff --git a/tests/mir-opt/gvn.slices.GVN.panic-abort.diff b/tests/mir-opt/gvn.slices.GVN.panic-abort.diff
index 2389d98b5b3..fb67e3d5994 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 = (*_15);
-+         _18 = (*_9);
++         _18 = _10;
           StorageLive(_19);
 -         _19 = (*_16);
-+         _19 = (*_12);
-          _17 = Eq(move _18, move _19);
+-         _17 = Eq(move _18, move _19);
++         _19 = _13;
++         _17 = Eq(_10, _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 = (*_41);
-+         _44 = (*_35);
++         _44 = _36;
           StorageLive(_45);
 -         _45 = (*_42);
-+         _45 = (*_38);
-          _43 = Eq(move _44, move _45);
+-         _43 = Eq(move _44, move _45);
++         _45 = _39;
++         _43 = Eq(_36, _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 50715d748e7..ae3013b011e 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 = (*_15);
-+         _18 = (*_9);
++         _18 = _10;
           StorageLive(_19);
 -         _19 = (*_16);
-+         _19 = (*_12);
-          _17 = Eq(move _18, move _19);
+-         _17 = Eq(move _18, move _19);
++         _19 = _13;
++         _17 = Eq(_10, _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 = (*_41);
-+         _44 = (*_35);
++         _44 = _36;
           StorageLive(_45);
 -         _45 = (*_42);
-+         _45 = (*_38);
-          _43 = Eq(move _44, move _45);
+-         _43 = Eq(move _44, move _45);
++         _45 = _39;
++         _43 = Eq(_36, _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 c5ee0d9c44d..626367766d7 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-abort.diff
@@ -17,7 +17,8 @@
           StorageLive(_3);
           _5 = const f::promoted[0];
           _3 = &(*_5);
-          _2 = ((*_3).1: E);
+-         _2 = ((*_3).1: E);
++         _2 = ((*_5).1: E);
           StorageLive(_1);
 -         _1 = ((_2 as A).1: u32);
 +         _1 = const 0_u32;
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 c5ee0d9c44d..626367766d7 100644
--- a/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn_uninhabited.f.GVN.panic-unwind.diff
@@ -17,7 +17,8 @@
           StorageLive(_3);
           _5 = const f::promoted[0];
           _3 = &(*_5);
-          _2 = ((*_3).1: E);
+-         _2 = ((*_3).1: E);
++         _2 = ((*_5).1: E);
           StorageLive(_1);
 -         _1 = ((_2 as A).1: u32);
 +         _1 = const 0_u32;
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 65cac0a81ef..dfa13230254 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
@@ -10,18 +10,18 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
     let mut _8: &&usize;
     let _9: &usize;
     let mut _10: &&usize;
-    let mut _15: bool;
+    let mut _13: bool;
+    let mut _14: &&usize;
+    let _15: &usize;
     let mut _16: &&usize;
-    let _17: &usize;
-    let mut _18: &&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;
-    let mut _31: bool;
-    let mut _32: &&usize;
-    let _33: &usize;
-    let mut _34: &&usize;
     scope 1 {
         debug a => _4;
         debug b => _5;
@@ -30,208 +30,145 @@ fn variant_a::{closure#0}(_1: &mut {closure@$DIR/slice_filter.rs:7:25: 7:39}, _2
         scope 2 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
             debug self => _8;
             debug other => _10;
-            let mut _11: &usize;
-            let mut _12: &usize;
             scope 3 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _11;
-                debug other => _12;
-                let mut _13: usize;
-                let mut _14: usize;
+                debug self => _4;
+                debug other => _9;
+                let mut _11: usize;
+                let mut _12: usize;
             }
         }
         scope 4 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _16;
-            debug other => _18;
-            let mut _19: &usize;
-            let mut _20: &usize;
+            debug self => _14;
+            debug other => _16;
             scope 5 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _19;
-                debug other => _20;
-                let mut _21: usize;
-                let mut _22: usize;
+                debug self => _7;
+                debug other => _15;
+                let mut _17: usize;
+                let mut _18: usize;
             }
         }
         scope 6 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _24;
-            debug other => _26;
-            let mut _27: &usize;
-            let mut _28: &usize;
+            debug self => _20;
+            debug other => _22;
             scope 7 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _27;
-                debug other => _28;
-                let mut _29: usize;
-                let mut _30: usize;
+                debug self => _6;
+                debug other => _21;
             }
         }
         scope 8 (inlined std::cmp::impls::<impl PartialOrd for &usize>::le) {
-            debug self => _32;
-            debug other => _34;
-            let mut _35: &usize;
-            let mut _36: &usize;
+            debug self => _24;
+            debug other => _26;
             scope 9 (inlined std::cmp::impls::<impl PartialOrd for usize>::le) {
-                debug self => _35;
-                debug other => _36;
-                let mut _37: usize;
-                let mut _38: usize;
+                debug self => _5;
+                debug other => _25;
+                let mut _27: usize;
+                let mut _28: usize;
             }
         }
     }
 
     bb0: {
-        StorageLive(_4);
         _3 = (*_2);
         _4 = &((*_3).0: usize);
-        StorageLive(_5);
         _5 = &((*_3).1: usize);
-        StorageLive(_6);
         _6 = &((*_3).2: usize);
-        StorageLive(_7);
         _7 = &((*_3).3: usize);
-        StorageLive(_15);
+        StorageLive(_13);
         StorageLive(_8);
         _8 = &_4;
         StorageLive(_10);
-        StorageLive(_9);
-        _9 = _6;
+        _9 = &((*_3).2: usize);
         _10 = &_9;
-        StorageLive(_11);
-        StorageLive(_12);
-        _11 = _4;
-        _12 = _9;
-        StorageLive(_13);
-        _13 = (*_11);
-        StorageLive(_14);
-        _14 = (*_12);
-        _15 = Le(move _13, move _14);
-        StorageDead(_14);
-        StorageDead(_13);
-        StorageDead(_12);
-        StorageDead(_11);
-        switchInt(move _15) -> [0: bb1, otherwise: bb2];
+        _11 = ((*_3).0: usize);
+        _12 = ((*_3).2: usize);
+        _13 = Le(_11, _12);
+        switchInt(move _13) -> [0: bb1, otherwise: bb2];
     }
 
     bb1: {
-        StorageDead(_9);
         StorageDead(_10);
         StorageDead(_8);
         goto -> bb4;
     }
 
     bb2: {
-        StorageDead(_9);
         StorageDead(_10);
         StorageDead(_8);
-        StorageLive(_23);
+        StorageLive(_19);
+        StorageLive(_14);
+        _14 = &_7;
         StorageLive(_16);
-        _16 = &_7;
-        StorageLive(_18);
+        _15 = &((*_3).1: usize);
+        _16 = &_15;
         StorageLive(_17);
-        _17 = _5;
-        _18 = &_17;
-        StorageLive(_19);
-        StorageLive(_20);
-        _19 = _7;
-        _20 = _17;
-        StorageLive(_21);
-        _21 = (*_19);
-        StorageLive(_22);
-        _22 = (*_20);
-        _23 = Le(move _21, move _22);
-        StorageDead(_22);
-        StorageDead(_21);
-        StorageDead(_20);
-        StorageDead(_19);
-        switchInt(move _23) -> [0: bb3, otherwise: bb8];
+        _17 = ((*_3).3: usize);
+        StorageLive(_18);
+        _18 = ((*_3).1: usize);
+        _19 = Le(move _17, move _18);
+        StorageDead(_18);
+        StorageDead(_17);
+        switchInt(move _19) -> [0: bb3, otherwise: bb8];
     }
 
     bb3: {
-        StorageDead(_17);
-        StorageDead(_18);
         StorageDead(_16);
+        StorageDead(_14);
         goto -> bb4;
     }
 
     bb4: {
-        StorageLive(_31);
-        StorageLive(_24);
-        _24 = &_6;
-        StorageLive(_26);
-        StorageLive(_25);
-        _25 = _4;
-        _26 = &_25;
-        StorageLive(_27);
-        StorageLive(_28);
-        _27 = _6;
-        _28 = _25;
-        StorageLive(_29);
-        _29 = (*_27);
-        StorageLive(_30);
-        _30 = (*_28);
-        _31 = Le(move _29, move _30);
-        StorageDead(_30);
-        StorageDead(_29);
-        StorageDead(_28);
-        StorageDead(_27);
-        switchInt(move _31) -> [0: bb5, otherwise: bb6];
+        StorageLive(_23);
+        StorageLive(_20);
+        _20 = &_6;
+        StorageLive(_22);
+        _21 = &((*_3).0: usize);
+        _22 = &_21;
+        _23 = Le(_12, _11);
+        switchInt(move _23) -> [0: bb5, otherwise: bb6];
     }
 
     bb5: {
-        StorageDead(_25);
-        StorageDead(_26);
-        StorageDead(_24);
+        StorageDead(_22);
+        StorageDead(_20);
         _0 = const false;
         goto -> bb7;
     }
 
     bb6: {
-        StorageDead(_25);
+        StorageDead(_22);
+        StorageDead(_20);
+        StorageLive(_24);
+        _24 = &_5;
+        StorageLive(_26);
+        _25 = &((*_3).3: usize);
+        _26 = &_25;
+        StorageLive(_27);
+        _27 = ((*_3).1: usize);
+        StorageLive(_28);
+        _28 = ((*_3).3: usize);
+        _0 = Le(move _27, move _28);
+        StorageDead(_28);
+        StorageDead(_27);
         StorageDead(_26);
         StorageDead(_24);
-        StorageLive(_32);
-        _32 = &_5;
-        StorageLive(_34);
-        StorageLive(_33);
-        _33 = _7;
-        _34 = &_33;
-        StorageLive(_35);
-        StorageLive(_36);
-        _35 = _5;
-        _36 = _33;
-        StorageLive(_37);
-        _37 = (*_35);
-        StorageLive(_38);
-        _38 = (*_36);
-        _0 = Le(move _37, move _38);
-        StorageDead(_38);
-        StorageDead(_37);
-        StorageDead(_36);
-        StorageDead(_35);
-        StorageDead(_33);
-        StorageDead(_34);
-        StorageDead(_32);
         goto -> bb7;
     }
 
     bb7: {
-        StorageDead(_31);
+        StorageDead(_23);
         goto -> bb9;
     }
 
     bb8: {
-        StorageDead(_17);
-        StorageDead(_18);
         StorageDead(_16);
+        StorageDead(_14);
         _0 = const true;
         goto -> bb9;
     }
 
     bb9: {
-        StorageDead(_23);
-        StorageDead(_15);
-        StorageDead(_7);
-        StorageDead(_6);
-        StorageDead(_5);
-        StorageDead(_4);
+        StorageDead(_19);
+        StorageDead(_13);
         return;
     }
 }
diff --git a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
index 1be2ce8d0bb..0dfe8781c18 100644
--- a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff
@@ -247,7 +247,8 @@
           StorageLive(_21);
           _21 = &_20;
           StorageLive(_22);
-          _22 = (*_20);
+-         _22 = (*_20);
++         _22 = _19;
           StorageLive(_23);
           StorageLive(_24);
           _24 = _21;
@@ -394,7 +395,8 @@
           StorageLive(_62);
           _62 = &_61;
           StorageLive(_63);
-          _63 = (*_61);
+-         _63 = (*_61);
++         _63 = _60;
           StorageLive(_64);
           StorageLive(_65);
           _65 = ();
diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
index 1e6a168f756..21486a8616a 100644
--- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
+++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff
@@ -260,7 +260,8 @@
           StorageLive(_20);
           _20 = &_19;
           StorageLive(_21);
-          _21 = (*_19);
+-         _21 = (*_19);
++         _21 = _18;
           StorageLive(_22);
           StorageLive(_23);
           _23 = _20;
@@ -429,7 +430,8 @@
           StorageLive(_67);
           _67 = &_66;
           StorageLive(_68);
-          _68 = (*_66);
+-         _68 = (*_66);
++         _68 = _65;
           StorageLive(_69);
           StorageLive(_70);
           _70 = ();
diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs
index 2dda771ba7d..e0b0d699420 100644
--- a/tests/mir-opt/reference_prop.rs
+++ b/tests/mir-opt/reference_prop.rs
@@ -49,7 +49,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) {
         // CHECK: [[a:_.*]] = const 5_usize;
         // CHECK: [[b:_.*]] = &[[a]];
         // CHECK: [[d:_.*]] = &[[b]];
-        // CHECK: [[c:_.*]] = (*[[b]]);
+        // CHECK: [[c:_.*]] = [[a]];
 
         let a = 5_usize;
         let b = &a;
@@ -138,8 +138,7 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) {
         // CHECK: [[a:_.*]] = const 5_usize;
         // CHECK: [[b:_.*]] = &[[a]];
         // CHECK: [[d:_.*]] = &[[b]];
-        // FIXME this could be [[a]]
-        // CHECK: [[c:_.*]] = (*[[b]]);
+        // CHECK: [[c:_.*]] = [[a]];
 
         let a = 5_usize;
         let b = &a;
@@ -363,7 +362,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con
         // CHECK: [[a:_.*]] = const 5_usize;
         // CHECK: [[b:_.*]] = &raw const [[a]];
         // CHECK: [[d:_.*]] = &[[b]];
-        // CHECK: [[c:_.*]] = (*[[b]]);
+        // CHECK: [[c:_.*]] = [[a]];
 
         let a = 5_usize;
         let b = &raw const a;
@@ -467,8 +466,7 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con
         // CHECK: [[a:_.*]] = const 5_usize;
         // CHECK: [[b:_.*]] = &raw const [[a]];
         // CHECK: [[d:_.*]] = &[[b]];
-        // FIXME this could be [[a]]
-        // CHECK: [[c:_.*]] = (*[[b]]);
+        // CHECK: [[c:_.*]] = [[a]];
 
         let a = 5_usize;
         let b = &raw const a;