about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs16
-rw-r--r--tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff3
-rw-r--r--tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff3
-rw-r--r--tests/mir-opt/gvn.rs2
4 files changed, 15 insertions, 9 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index a0fb20d1844..8b8d1efbbd2 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -980,7 +980,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
-        if let Some(place) = self.try_as_place(copy_from_local_value, location) {
+        // Allow introducing places with non-constant offsets, as those are still better than
+        // reconstructing an aggregate.
+        if let Some(place) = self.try_as_place(copy_from_local_value, location, true) {
             if rvalue.ty(self.local_decls, self.tcx) == place.ty(self.local_decls, self.tcx).ty {
                 self.reused_locals.insert(place.local);
                 *rvalue = Rvalue::Use(Operand::Copy(place));
@@ -1665,7 +1667,7 @@ impl<'tcx> VnState<'_, 'tcx> {
     fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option<Operand<'tcx>> {
         if let Some(const_) = self.try_as_constant(index) {
             Some(Operand::Constant(Box::new(const_)))
-        } else if let Some(place) = self.try_as_place(index, location) {
+        } else if let Some(place) = self.try_as_place(index, location, false) {
             self.reused_locals.insert(place.local);
             Some(Operand::Copy(place))
         } else {
@@ -1704,7 +1706,12 @@ impl<'tcx> VnState<'_, 'tcx> {
     /// dominate `loc`. If you used this place, add its base local to `reused_locals` to remove
     /// storage statements.
     #[instrument(level = "trace", skip(self), ret)]
-    fn try_as_place(&mut self, mut index: VnIndex, loc: Location) -> Option<Place<'tcx>> {
+    fn try_as_place(
+        &mut self,
+        mut index: VnIndex,
+        loc: Location,
+        allow_complex_projection: bool,
+    ) -> Option<Place<'tcx>> {
         let mut projection = SmallVec::<[PlaceElem<'tcx>; 1]>::new();
         loop {
             if let Some(local) = self.try_as_local(index, loc) {
@@ -1713,6 +1720,7 @@ impl<'tcx> VnState<'_, 'tcx> {
                     Place { local, projection: self.tcx.mk_place_elems(projection.as_slice()) };
                 return Some(place);
             } else if let Value::Projection(pointer, proj) = *self.get(index)
+                && (allow_complex_projection || proj.is_stable_offset())
                 && let Some(proj) = self.try_as_place_elem(proj, loc)
             {
                 projection.push(proj);
@@ -1773,7 +1781,7 @@ impl<'tcx> MutVisitor<'tcx> for VnState<'_, 'tcx> {
             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(place) = self.try_as_place(value, location)
+                } else if let Some(place) = self.try_as_place(value, location, false)
                     && *rvalue != Rvalue::Use(Operand::Move(place))
                     && *rvalue != Rvalue::Use(Operand::Copy(place))
                 {
diff --git a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff
index 545a1e350b8..98cb34810bc 100644
--- a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff
@@ -9,8 +9,7 @@
       bb0: {
           _3 = copy (*_1) as *const u8 (PtrToPtr);
           _4 = copy _2 as *const u8 (PtrToPtr);
--         _0 = Eq(copy _3, copy _4);
-+         _0 = Eq(copy (*_1), copy _2);
+          _0 = Eq(copy _3, copy _4);
           return;
       }
   }
diff --git a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff
index 545a1e350b8..98cb34810bc 100644
--- a/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff
@@ -9,8 +9,7 @@
       bb0: {
           _3 = copy (*_1) as *const u8 (PtrToPtr);
           _4 = copy _2 as *const u8 (PtrToPtr);
--         _0 = Eq(copy _3, copy _4);
-+         _0 = Eq(copy (*_1), copy _2);
+          _0 = Eq(copy _3, copy _4);
           return;
       }
   }
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index fa263091a81..6ef320c90de 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -1048,7 +1048,7 @@ fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool
             let a = *mut_a as *const u8;
             // CHECK: [[B:_.+]] = copy _2 as *const u8 (PtrToPtr);
             let b = mut_b as *const u8;
-            // CHECK: _0 = Eq(copy (*_1), copy _2);
+            // CHECK: _0 = Eq(copy [[A]], copy [[B]]);
             RET = a == b;
             Return()
         }