about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-07-01 08:53:06 +0200
committerGitHub <noreply@github.com>2024-07-01 08:53:06 +0200
commit6938b4b64059aab458a4fa9585b770d776e04c19 (patch)
tree1415be445567e2a5ed962e48155e209a853614e0
parent04a3969af7c2c8bea18ce53339dbb4802438577c (diff)
parentf6942112eb44cb292463d457c603016cc16f4bc6 (diff)
downloadrust-6938b4b64059aab458a4fa9585b770d776e04c19.tar.gz
rust-6938b4b64059aab458a4fa9585b770d776e04c19.zip
Rollup merge of #127105 - scottmcm:issue-127089, r=cjgillot
Only update `Eq` operands in GVN if it can update both sides

Otherwise the types might not match

Fixes #127089

r? mir-opt
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs10
-rw-r--r--tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff16
-rw-r--r--tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff16
-rw-r--r--tests/mir-opt/gvn.rs20
-rw-r--r--tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff52
-rw-r--r--tests/mir-opt/gvn_ptr_eq_with_constant.rs23
6 files changed, 132 insertions, 5 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 936a7e2d9de..3dbdeb615cf 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -1074,11 +1074,11 @@ impl<'body, 'tcx> VnState<'body, '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(lhs_op) = self.try_as_operand(lhs, location)
+                && let Some(rhs_op) = self.try_as_operand(rhs, location)
+            {
+                *lhs_operand = lhs_op;
+                *rhs_operand = rhs_op;
             }
         }
 
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
new file mode 100644
index 00000000000..8b4bfb70401
--- /dev/null
+++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-abort.diff
@@ -0,0 +1,16 @@
+- // MIR for `remove_casts_must_change_both_sides` before GVN
++ // MIR for `remove_casts_must_change_both_sides` after GVN
+  
+  fn remove_casts_must_change_both_sides(_1: &*mut u8, _2: *mut u8) -> bool {
+      let mut _0: bool;
+      let mut _3: *const u8;
+      let mut _4: *const u8;
+  
+      bb0: {
+          _3 = (*_1) as *const u8 (PtrToPtr);
+          _4 = _2 as *const u8 (PtrToPtr);
+          _0 = Eq(_3, _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
new file mode 100644
index 00000000000..8b4bfb70401
--- /dev/null
+++ b/tests/mir-opt/gvn.remove_casts_must_change_both_sides.GVN.panic-unwind.diff
@@ -0,0 +1,16 @@
+- // MIR for `remove_casts_must_change_both_sides` before GVN
++ // MIR for `remove_casts_must_change_both_sides` after GVN
+  
+  fn remove_casts_must_change_both_sides(_1: &*mut u8, _2: *mut u8) -> bool {
+      let mut _0: bool;
+      let mut _3: *const u8;
+      let mut _4: *const u8;
+  
+      bb0: {
+          _3 = (*_1) as *const u8 (PtrToPtr);
+          _4 = _2 as *const u8 (PtrToPtr);
+          _0 = Eq(_3, _4);
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 86f42d23f38..c7fae0bd081 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -926,6 +926,25 @@ unsafe fn cast_pointer_then_transmute(thin: *mut u32, fat: *mut [u8]) {
     let fat_addr: usize = std::intrinsics::transmute(fat as *const ());
 }
 
+#[custom_mir(dialect = "analysis")]
+fn remove_casts_must_change_both_sides(mut_a: &*mut u8, mut_b: *mut u8) -> bool {
+    // CHECK-LABEL: fn remove_casts_must_change_both_sides(
+    mir! {
+        // We'd like to remove these casts, but we can't change *both* of them
+        // to be locals, so make sure we don't change one without the other, as
+        // that would be a type error.
+        {
+            // CHECK: [[A:_.+]] = (*_1) as *const u8 (PtrToPtr);
+            let a = *mut_a as *const u8;
+            // CHECK: [[B:_.+]] = _2 as *const u8 (PtrToPtr);
+            let b = mut_b as *const u8;
+            // CHECK: _0 = Eq([[A]], [[B]]);
+            RET = a == b;
+            Return()
+        }
+    }
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
@@ -995,3 +1014,4 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.generic_cast_metadata.GVN.diff
 // EMIT_MIR gvn.cast_pointer_eq.GVN.diff
 // EMIT_MIR gvn.cast_pointer_then_transmute.GVN.diff
+// EMIT_MIR gvn.remove_casts_must_change_both_sides.GVN.diff
diff --git a/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff
new file mode 100644
index 00000000000..3af78d9b6ce
--- /dev/null
+++ b/tests/mir-opt/gvn_ptr_eq_with_constant.main.GVN.diff
@@ -0,0 +1,52 @@
+- // MIR for `main` before GVN
++ // MIR for `main` after GVN
+  
+  fn main() -> () {
+      let mut _0: ();
+      let _1: bool;
+      let mut _2: *mut u8;
+      scope 1 (inlined dangling_mut::<u8>) {
+          let mut _3: usize;
+          scope 2 (inlined align_of::<u8>) {
+          }
+          scope 3 (inlined without_provenance_mut::<u8>) {
+          }
+      }
+      scope 4 (inlined Foo::<u8>::cmp_ptr) {
+          let mut _4: *const u8;
+          let mut _5: *mut u8;
+          let mut _6: *const u8;
+          scope 5 (inlined std::ptr::eq::<u8>) {
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          StorageLive(_2);
+          StorageLive(_3);
+-         _3 = AlignOf(u8);
+-         _2 = _3 as *mut u8 (Transmute);
++         _3 = const 1_usize;
++         _2 = const {0x1 as *mut u8};
+          StorageDead(_3);
+          StorageLive(_4);
+          StorageLive(_5);
+-         _5 = _2;
+-         _4 = _2 as *const u8 (PtrToPtr);
++         _5 = const {0x1 as *mut u8};
++         _4 = const {0x1 as *const u8};
+          StorageDead(_5);
+          StorageLive(_6);
+-         _6 = const Foo::<u8>::SENTINEL as *const u8 (PtrToPtr);
+-         _1 = Eq(_4, _6);
++         _6 = const {0x1 as *const u8};
++         _1 = const true;
+          StorageDead(_6);
+          StorageDead(_4);
+          StorageDead(_2);
+          StorageDead(_1);
+          _0 = const ();
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_ptr_eq_with_constant.rs b/tests/mir-opt/gvn_ptr_eq_with_constant.rs
new file mode 100644
index 00000000000..d8025072ee3
--- /dev/null
+++ b/tests/mir-opt/gvn_ptr_eq_with_constant.rs
@@ -0,0 +1,23 @@
+// skip-filecheck
+//@ test-mir-pass: GVN
+//@ only-64bit
+//@ compile-flags: -Z mir-enable-passes=+Inline
+
+// Regression for <https://github.com/rust-lang/rust/issues/127089>
+
+#![feature(strict_provenance)]
+
+struct Foo<T>(std::marker::PhantomData<T>);
+
+impl<T> Foo<T> {
+    const SENTINEL: *mut T = std::ptr::dangling_mut();
+
+    fn cmp_ptr(a: *mut T) -> bool {
+        std::ptr::eq(a, Self::SENTINEL)
+    }
+}
+
+// EMIT_MIR gvn_ptr_eq_with_constant.main.GVN.diff
+pub fn main() {
+    Foo::<u8>::cmp_ptr(std::ptr::dangling_mut());
+}