about summary refs log tree commit diff
diff options
context:
space:
mode:
authorScott McMurray <scottmcm@users.noreply.github.com>2024-06-22 13:45:14 -0700
committerScott McMurray <scottmcm@users.noreply.github.com>2024-06-22 20:27:08 -0700
commitdd1e19e7c22c1a670501cb7e8b9a036d8aa3af5d (patch)
tree7c66bcc074f24d1e95a0f6d25dfdfa00143a8cc9
parenta76e1d9b09ece967c01aafd3f8419f579a7ac5ca (diff)
downloadrust-dd1e19e7c22c1a670501cb7e8b9a036d8aa3af5d.tar.gz
rust-dd1e19e7c22c1a670501cb7e8b9a036d8aa3af5d.zip
GVN away PtrToPtr before comparisons
Notably this happens in `NonNull::eq` :/
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs59
-rw-r--r--tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff134
-rw-r--r--tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff134
-rw-r--r--tests/mir-opt/gvn.rs31
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir44
-rw-r--r--tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir44
6 files changed, 382 insertions, 64 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 23124523f17..cf1fff97f2a 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -823,18 +823,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 return self.simplify_cast(kind, value, to, location);
             }
             Rvalue::BinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
-                let ty = lhs.ty(self.local_decls, self.tcx);
-                let lhs = self.simplify_operand(lhs, location);
-                let rhs = self.simplify_operand(rhs, location);
-                // Only short-circuit options after we called `simplify_operand`
-                // on both operands for side effect.
-                let lhs = lhs?;
-                let rhs = rhs?;
-
-                if let Some(value) = self.simplify_binary(op, ty, lhs, rhs) {
-                    return Some(value);
-                }
-                Value::BinaryOp(op, lhs, rhs)
+                return self.simplify_binary(op, lhs, rhs, location);
             }
             Rvalue::UnaryOp(op, ref mut arg_op) => {
                 return self.simplify_unary(op, arg_op, location);
@@ -1061,6 +1050,52 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
     fn simplify_binary(
         &mut self,
         op: BinOp,
+        lhs_operand: &mut Operand<'tcx>,
+        rhs_operand: &mut Operand<'tcx>,
+        location: Location,
+    ) -> Option<VnIndex> {
+
+        let lhs = self.simplify_operand(lhs_operand, location);
+        let rhs = self.simplify_operand(rhs_operand, location);
+        // Only short-circuit options after we called `simplify_operand`
+        // on both operands for side effect.
+        let mut lhs = lhs?;
+        let mut rhs = rhs?;
+
+        let lhs_ty = lhs_operand.ty(self.local_decls, self.tcx);
+
+        // If we're comparing pointers, remove `PtrToPtr` casts if the from
+        // types of both casts and the metadata all match.
+        if let BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge = op
+            && lhs_ty.is_any_ptr()
+            && let Value::Cast { kind: CastKind::PtrToPtr, value: lhs_value, from: lhs_from, .. } =
+                self.get(lhs)
+            && let Value::Cast { kind: CastKind::PtrToPtr, value: rhs_value, from: rhs_from, .. } =
+                self.get(rhs)
+            && lhs_from == rhs_from
+            && lhs_from.pointee_metadata_ty_or_projection(self.tcx)
+                == lhs_ty.pointee_metadata_ty_or_projection(self.tcx)
+        {
+            lhs = *lhs_value;
+            rhs = *rhs_value;
+            if let Some(op) = self.try_as_operand(lhs, location) {
+                *lhs_operand = op;
+            }
+            if let Some(op) = self.try_as_operand(rhs, location) {
+                *rhs_operand = op;
+            }
+        }
+
+        if let Some(value) = self.simplify_binary_inner(op, lhs_ty, lhs, rhs) {
+            return Some(value);
+        }
+        let value = Value::BinaryOp(op, lhs, rhs);
+        Some(self.insert(value))
+    }
+
+    fn simplify_binary_inner(
+        &mut self,
+        op: BinOp,
         lhs_ty: Ty<'tcx>,
         lhs: VnIndex,
         rhs: VnIndex,
diff --git a/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff
new file mode 100644
index 00000000000..757ab959813
--- /dev/null
+++ b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-abort.diff
@@ -0,0 +1,134 @@
+- // MIR for `cast_pointer_eq` before GVN
++ // MIR for `cast_pointer_eq` after GVN
+  
+  fn cast_pointer_eq(_1: *mut u8, _2: *mut u32, _3: *mut u32, _4: *mut [u32]) -> () {
+      debug p1 => _1;
+      debug p2 => _2;
+      debug p3 => _3;
+      debug p4 => _4;
+      let mut _0: ();
+      let _5: *const u32;
+      let mut _6: *mut u8;
+      let mut _8: *const u32;
+      let mut _9: *mut u32;
+      let mut _11: *const u32;
+      let mut _12: *mut u32;
+      let mut _14: *mut [u32];
+      let mut _16: *const u32;
+      let mut _17: *const u32;
+      let mut _19: *const u32;
+      let mut _20: *const u32;
+      let mut _22: *const u32;
+      let mut _23: *const u32;
+      scope 1 {
+          debug m1 => _5;
+          let _7: *const u32;
+          scope 2 {
+              debug m2 => _7;
+              let _10: *const u32;
+              scope 3 {
+                  debug m3 => _10;
+                  let _13: *const u32;
+                  scope 4 {
+                      debug m4 => _13;
+                      let _15: bool;
+                      scope 5 {
+                          debug eq_different_thing => _15;
+                          let _18: bool;
+                          scope 6 {
+                              debug eq_optimize => _18;
+                              let _21: bool;
+                              scope 7 {
+                                  debug eq_thin_fat => _21;
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_5);
++         nop;
+          StorageLive(_6);
+          _6 = _1;
+-         _5 = move _6 as *const u32 (PtrToPtr);
++         _5 = _1 as *const u32 (PtrToPtr);
+          StorageDead(_6);
+          StorageLive(_7);
+-         StorageLive(_8);
++         nop;
+          StorageLive(_9);
+          _9 = _2;
+-         _8 = move _9 as *const u32 (PtrToPtr);
++         _8 = _2 as *const u32 (PtrToPtr);
+          StorageDead(_9);
+-         _7 = move _8 as *const u32 (PtrToPtr);
+-         StorageDead(_8);
++         _7 = _8;
++         nop;
+          StorageLive(_10);
+-         StorageLive(_11);
++         nop;
+          StorageLive(_12);
+          _12 = _3;
+-         _11 = move _12 as *const u32 (PtrToPtr);
++         _11 = _3 as *const u32 (PtrToPtr);
+          StorageDead(_12);
+-         _10 = move _11 as *const u32 (PtrToPtr);
+-         StorageDead(_11);
+-         StorageLive(_13);
++         _10 = _11;
++         nop;
++         nop;
+          StorageLive(_14);
+          _14 = _4;
+-         _13 = move _14 as *const u32 (PtrToPtr);
++         _13 = _4 as *const u32 (PtrToPtr);
+          StorageDead(_14);
+          StorageLive(_15);
+          StorageLive(_16);
+          _16 = _5;
+          StorageLive(_17);
+-         _17 = _7;
+-         _15 = Eq(move _16, move _17);
++         _17 = _8;
++         _15 = Eq(_5, _8);
+          StorageDead(_17);
+          StorageDead(_16);
+          StorageLive(_18);
+          StorageLive(_19);
+-         _19 = _7;
++         _19 = _8;
+          StorageLive(_20);
+-         _20 = _10;
+-         _18 = Eq(move _19, move _20);
++         _20 = _11;
++         _18 = Eq(_2, _3);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageLive(_21);
+          StorageLive(_22);
+-         _22 = _10;
++         _22 = _11;
+          StorageLive(_23);
+          _23 = _13;
+-         _21 = Eq(move _22, move _23);
++         _21 = Eq(_11, _13);
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+          StorageDead(_21);
+          StorageDead(_18);
+          StorageDead(_15);
+-         StorageDead(_13);
++         nop;
+          StorageDead(_10);
+          StorageDead(_7);
+-         StorageDead(_5);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..757ab959813
--- /dev/null
+++ b/tests/mir-opt/gvn.cast_pointer_eq.GVN.panic-unwind.diff
@@ -0,0 +1,134 @@
+- // MIR for `cast_pointer_eq` before GVN
++ // MIR for `cast_pointer_eq` after GVN
+  
+  fn cast_pointer_eq(_1: *mut u8, _2: *mut u32, _3: *mut u32, _4: *mut [u32]) -> () {
+      debug p1 => _1;
+      debug p2 => _2;
+      debug p3 => _3;
+      debug p4 => _4;
+      let mut _0: ();
+      let _5: *const u32;
+      let mut _6: *mut u8;
+      let mut _8: *const u32;
+      let mut _9: *mut u32;
+      let mut _11: *const u32;
+      let mut _12: *mut u32;
+      let mut _14: *mut [u32];
+      let mut _16: *const u32;
+      let mut _17: *const u32;
+      let mut _19: *const u32;
+      let mut _20: *const u32;
+      let mut _22: *const u32;
+      let mut _23: *const u32;
+      scope 1 {
+          debug m1 => _5;
+          let _7: *const u32;
+          scope 2 {
+              debug m2 => _7;
+              let _10: *const u32;
+              scope 3 {
+                  debug m3 => _10;
+                  let _13: *const u32;
+                  scope 4 {
+                      debug m4 => _13;
+                      let _15: bool;
+                      scope 5 {
+                          debug eq_different_thing => _15;
+                          let _18: bool;
+                          scope 6 {
+                              debug eq_optimize => _18;
+                              let _21: bool;
+                              scope 7 {
+                                  debug eq_thin_fat => _21;
+                              }
+                          }
+                      }
+                  }
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_5);
++         nop;
+          StorageLive(_6);
+          _6 = _1;
+-         _5 = move _6 as *const u32 (PtrToPtr);
++         _5 = _1 as *const u32 (PtrToPtr);
+          StorageDead(_6);
+          StorageLive(_7);
+-         StorageLive(_8);
++         nop;
+          StorageLive(_9);
+          _9 = _2;
+-         _8 = move _9 as *const u32 (PtrToPtr);
++         _8 = _2 as *const u32 (PtrToPtr);
+          StorageDead(_9);
+-         _7 = move _8 as *const u32 (PtrToPtr);
+-         StorageDead(_8);
++         _7 = _8;
++         nop;
+          StorageLive(_10);
+-         StorageLive(_11);
++         nop;
+          StorageLive(_12);
+          _12 = _3;
+-         _11 = move _12 as *const u32 (PtrToPtr);
++         _11 = _3 as *const u32 (PtrToPtr);
+          StorageDead(_12);
+-         _10 = move _11 as *const u32 (PtrToPtr);
+-         StorageDead(_11);
+-         StorageLive(_13);
++         _10 = _11;
++         nop;
++         nop;
+          StorageLive(_14);
+          _14 = _4;
+-         _13 = move _14 as *const u32 (PtrToPtr);
++         _13 = _4 as *const u32 (PtrToPtr);
+          StorageDead(_14);
+          StorageLive(_15);
+          StorageLive(_16);
+          _16 = _5;
+          StorageLive(_17);
+-         _17 = _7;
+-         _15 = Eq(move _16, move _17);
++         _17 = _8;
++         _15 = Eq(_5, _8);
+          StorageDead(_17);
+          StorageDead(_16);
+          StorageLive(_18);
+          StorageLive(_19);
+-         _19 = _7;
++         _19 = _8;
+          StorageLive(_20);
+-         _20 = _10;
+-         _18 = Eq(move _19, move _20);
++         _20 = _11;
++         _18 = Eq(_2, _3);
+          StorageDead(_20);
+          StorageDead(_19);
+          StorageLive(_21);
+          StorageLive(_22);
+-         _22 = _10;
++         _22 = _11;
+          StorageLive(_23);
+          _23 = _13;
+-         _21 = Eq(move _22, move _23);
++         _21 = Eq(_11, _13);
+          StorageDead(_23);
+          StorageDead(_22);
+          _0 = const ();
+          StorageDead(_21);
+          StorageDead(_18);
+          StorageDead(_15);
+-         StorageDead(_13);
++         nop;
+          StorageDead(_10);
+          StorageDead(_7);
+-         StorageDead(_5);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 8bc2550b8f5..6f1580b49ed 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -883,6 +883,36 @@ fn generic_cast_metadata<T, A: ?Sized, B: ?Sized>(ps: *const [T], pa: *const A,
     }
 }
 
+fn cast_pointer_eq(p1: *mut u8, p2: *mut u32, p3: *mut u32, p4: *mut [u32]) {
+    // CHECK-LABEL: fn cast_pointer_eq
+    // CHECK: debug p1 => [[P1:_1]];
+    // CHECK: debug p2 => [[P2:_2]];
+    // CHECK: debug p3 => [[P3:_3]];
+    // CHECK: debug p4 => [[P4:_4]];
+
+    // CHECK: [[M1:_.+]] = [[P1]] as *const u32 (PtrToPtr);
+    // CHECK: [[M2:_.+]] = [[P2]] as *const u32 (PtrToPtr);
+    // CHECK: [[M3:_.+]] = [[P3]] as *const u32 (PtrToPtr);
+    // CHECK: [[M4:_.+]] = [[P4]] as *const u32 (PtrToPtr);
+    let m1 = p1 as *const u32;
+    let m2 = p2 as *const u32;
+    let m3 = p3 as *const u32;
+    let m4 = p4 as *const u32;
+
+    // CHECK-NOT: Eq
+    // CHECK: Eq([[M1]], [[M2]])
+    // CHECK-NOT: Eq
+    // CHECK: Eq([[P2]], [[P3]])
+    // CHECK-NOT: Eq
+    // CHECK: Eq([[M3]], [[M4]])
+    // CHECK-NOT: Eq
+    let eq_different_thing = m1 == m2;
+    let eq_optimize = m2 == m3;
+    let eq_thin_fat = m3 == m4;
+
+    // CHECK: _0 = const ();
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
@@ -950,3 +980,4 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.manual_slice_mut_len.GVN.diff
 // EMIT_MIR gvn.array_len.GVN.diff
 // EMIT_MIR gvn.generic_cast_metadata.GVN.diff
+// EMIT_MIR gvn.cast_pointer_eq.GVN.diff
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir
index 5988a0a03ef..19548beaf2a 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-abort.mir
@@ -6,27 +6,25 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
     scope 1 (inlined <std::slice::Iter<'_, T> as ExactSizeIterator>::is_empty) {
         let mut _2: *const *const T;
         let mut _3: *const std::ptr::NonNull<T>;
-        let mut _10: *const T;
+        let mut _8: *const T;
         scope 2 {
             let _4: std::ptr::NonNull<T>;
-            let _12: usize;
+            let _10: usize;
             scope 3 {
             }
             scope 4 {
                 scope 8 (inlined <NonNull<T> as PartialEq>::eq) {
                     let mut _5: std::ptr::NonNull<T>;
-                    let mut _7: *mut T;
-                    let mut _9: *mut T;
                     scope 9 (inlined NonNull::<T>::as_ptr) {
                         let mut _6: *const T;
                     }
                     scope 10 (inlined NonNull::<T>::as_ptr) {
-                        let mut _8: *const T;
+                        let mut _7: *const T;
                     }
                 }
             }
             scope 5 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
-                let mut _11: *const ();
+                let mut _9: *const ();
                 scope 6 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
                 }
             }
@@ -36,7 +34,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
     }
 
     bb0: {
-        StorageLive(_12);
+        StorageLive(_10);
         StorageLive(_4);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
@@ -49,40 +47,34 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
         StorageDead(_2);
         _4 = (*_3);
         StorageDead(_3);
+        StorageLive(_6);
         StorageLive(_7);
         StorageLive(_5);
         _5 = ((*_1).0: std::ptr::NonNull<T>);
-        StorageLive(_6);
         _6 = (_5.0: *const T);
-        _7 = move _6 as *mut T (PtrToPtr);
-        StorageDead(_6);
         StorageDead(_5);
-        StorageLive(_9);
-        StorageLive(_8);
-        _8 = (_4.0: *const T);
-        _9 = move _8 as *mut T (PtrToPtr);
-        StorageDead(_8);
-        _0 = Eq(move _7, move _9);
-        StorageDead(_9);
+        _7 = (_4.0: *const T);
+        _0 = Eq(_6, _7);
         StorageDead(_7);
+        StorageDead(_6);
         goto -> bb3;
     }
 
     bb2: {
-        StorageLive(_10);
-        _10 = ((*_1).1: *const T);
-        StorageLive(_11);
-        _11 = _10 as *const () (PtrToPtr);
-        _12 = move _11 as usize (Transmute);
-        StorageDead(_11);
-        StorageDead(_10);
-        _0 = Eq(_12, const 0_usize);
+        StorageLive(_8);
+        _8 = ((*_1).1: *const T);
+        StorageLive(_9);
+        _9 = _8 as *const () (PtrToPtr);
+        _10 = move _9 as usize (Transmute);
+        StorageDead(_9);
+        StorageDead(_8);
+        _0 = Eq(_10, const 0_usize);
         goto -> bb3;
     }
 
     bb3: {
         StorageDead(_4);
-        StorageDead(_12);
+        StorageDead(_10);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir
index 5988a0a03ef..19548beaf2a 100644
--- a/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_iter.slice_iter_generic_is_empty.PreCodegen.after.panic-unwind.mir
@@ -6,27 +6,25 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
     scope 1 (inlined <std::slice::Iter<'_, T> as ExactSizeIterator>::is_empty) {
         let mut _2: *const *const T;
         let mut _3: *const std::ptr::NonNull<T>;
-        let mut _10: *const T;
+        let mut _8: *const T;
         scope 2 {
             let _4: std::ptr::NonNull<T>;
-            let _12: usize;
+            let _10: usize;
             scope 3 {
             }
             scope 4 {
                 scope 8 (inlined <NonNull<T> as PartialEq>::eq) {
                     let mut _5: std::ptr::NonNull<T>;
-                    let mut _7: *mut T;
-                    let mut _9: *mut T;
                     scope 9 (inlined NonNull::<T>::as_ptr) {
                         let mut _6: *const T;
                     }
                     scope 10 (inlined NonNull::<T>::as_ptr) {
-                        let mut _8: *const T;
+                        let mut _7: *const T;
                     }
                 }
             }
             scope 5 (inlined std::ptr::const_ptr::<impl *const T>::addr) {
-                let mut _11: *const ();
+                let mut _9: *const ();
                 scope 6 (inlined std::ptr::const_ptr::<impl *const T>::cast::<()>) {
                 }
             }
@@ -36,7 +34,7 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
     }
 
     bb0: {
-        StorageLive(_12);
+        StorageLive(_10);
         StorageLive(_4);
         switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2];
     }
@@ -49,40 +47,34 @@ fn slice_iter_generic_is_empty(_1: &std::slice::Iter<'_, T>) -> bool {
         StorageDead(_2);
         _4 = (*_3);
         StorageDead(_3);
+        StorageLive(_6);
         StorageLive(_7);
         StorageLive(_5);
         _5 = ((*_1).0: std::ptr::NonNull<T>);
-        StorageLive(_6);
         _6 = (_5.0: *const T);
-        _7 = move _6 as *mut T (PtrToPtr);
-        StorageDead(_6);
         StorageDead(_5);
-        StorageLive(_9);
-        StorageLive(_8);
-        _8 = (_4.0: *const T);
-        _9 = move _8 as *mut T (PtrToPtr);
-        StorageDead(_8);
-        _0 = Eq(move _7, move _9);
-        StorageDead(_9);
+        _7 = (_4.0: *const T);
+        _0 = Eq(_6, _7);
         StorageDead(_7);
+        StorageDead(_6);
         goto -> bb3;
     }
 
     bb2: {
-        StorageLive(_10);
-        _10 = ((*_1).1: *const T);
-        StorageLive(_11);
-        _11 = _10 as *const () (PtrToPtr);
-        _12 = move _11 as usize (Transmute);
-        StorageDead(_11);
-        StorageDead(_10);
-        _0 = Eq(_12, const 0_usize);
+        StorageLive(_8);
+        _8 = ((*_1).1: *const T);
+        StorageLive(_9);
+        _9 = _8 as *const () (PtrToPtr);
+        _10 = move _9 as usize (Transmute);
+        StorageDead(_9);
+        StorageDead(_8);
+        _0 = Eq(_10, const 0_usize);
         goto -> bb3;
     }
 
     bb3: {
         StorageDead(_4);
-        StorageDead(_12);
+        StorageDead(_10);
         return;
     }
 }