about summary refs log tree commit diff
diff options
context:
space:
mode:
author许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com>2024-06-09 19:16:19 +0100
committerGitHub <noreply@github.com>2024-06-09 19:16:19 +0100
commitf000b428bd0cb642422f2fea815a33cda971b1fe (patch)
tree9257a0e921506a2dc201e6441d4a5ad2f150bcba
parent7bb0ef4902e43f338aa73c3ff728bea3cb9ecf6a (diff)
parent021ccf6c4ed0ae32f66b06a06f542c83f4e81670 (diff)
downloadrust-f000b428bd0cb642422f2fea815a33cda971b1fe.tar.gz
rust-f000b428bd0cb642422f2fea815a33cda971b1fe.zip
Rollup merge of #125041 - scottmcm:gvn-for-from-raw-parts, r=cjgillot
Enable GVN for `AggregateKind::RawPtr`

Looks like I was worried for nothing; this seems like it's much easier than I was originally thinking it would be.
r? `@cjgillot`

This should be useful for `x[..4]`-like things, should those start inlining enough to expose the lengths.
-rw-r--r--compiler/rustc_mir_transform/src/gvn.rs99
-rw-r--r--tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff60
-rw-r--r--tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff60
-rw-r--r--tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff32
-rw-r--r--tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff32
-rw-r--r--tests/mir-opt/gvn.rs40
-rw-r--r--tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff48
-rw-r--r--tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff48
-rw-r--r--tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff51
-rw-r--r--tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff51
-rw-r--r--tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir10
-rw-r--r--tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir10
-rw-r--r--tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir2
-rw-r--r--tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir2
14 files changed, 519 insertions, 26 deletions
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index ebfb372329e..459d15b1cac 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -83,8 +83,8 @@
 //! that contain `AllocId`s.
 
 use rustc_const_eval::const_eval::DummyMachine;
-use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemoryKind};
-use rustc_const_eval::interpret::{ImmTy, InterpCx, OpTy, Projectable, Scalar};
+use rustc_const_eval::interpret::{intern_const_alloc_for_constprop, MemPlaceMeta, MemoryKind};
+use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, Projectable, Scalar};
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_hir::def::DefKind;
@@ -99,7 +99,7 @@ use rustc_middle::ty::layout::{HasParamEnv, LayoutOf};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
-use rustc_target::abi::{self, Abi, Size, VariantIdx, FIRST_VARIANT};
+use rustc_target::abi::{self, Abi, FieldIdx, Size, VariantIdx, FIRST_VARIANT};
 use smallvec::SmallVec;
 use std::borrow::Cow;
 
@@ -177,6 +177,12 @@ enum AggregateTy<'tcx> {
     Array,
     Tuple,
     Def(DefId, ty::GenericArgsRef<'tcx>),
+    RawPtr {
+        /// Needed for cast propagation.
+        data_pointer_ty: Ty<'tcx>,
+        /// The data pointer can be anything thin, so doesn't determine the output.
+        output_pointer_ty: Ty<'tcx>,
+    },
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
@@ -385,11 +391,22 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                     AggregateTy::Def(def_id, args) => {
                         self.tcx.type_of(def_id).instantiate(self.tcx, args)
                     }
+                    AggregateTy::RawPtr { output_pointer_ty, .. } => output_pointer_ty,
                 };
                 let variant = if ty.is_enum() { Some(variant) } else { None };
                 let ty = self.ecx.layout_of(ty).ok()?;
                 if ty.is_zst() {
                     ImmTy::uninit(ty).into()
+                } else if matches!(kind, AggregateTy::RawPtr { .. }) {
+                    // Pointers don't have fields, so don't `project_field` them.
+                    let data = self.ecx.read_pointer(fields[0]).ok()?;
+                    let meta = if fields[1].layout.is_zst() {
+                        MemPlaceMeta::None
+                    } else {
+                        MemPlaceMeta::Meta(self.ecx.read_scalar(fields[1]).ok()?)
+                    };
+                    let ptr_imm = Immediate::new_pointer_with_meta(data, meta, &self.ecx);
+                    ImmTy::from_immediate(ptr_imm, ty).into()
                 } else if matches!(ty.abi, Abi::Scalar(..) | Abi::ScalarPair(..)) {
                     let dest = self.ecx.allocate(ty, MemoryKind::Stack).ok()?;
                     let variant_dest = if let Some(variant) = variant {
@@ -864,10 +881,10 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
         rvalue: &mut Rvalue<'tcx>,
         location: Location,
     ) -> Option<VnIndex> {
-        let Rvalue::Aggregate(box ref kind, ref mut fields) = *rvalue else { bug!() };
+        let Rvalue::Aggregate(box ref kind, ref mut field_ops) = *rvalue else { bug!() };
 
         let tcx = self.tcx;
-        if fields.is_empty() {
+        if field_ops.is_empty() {
             let is_zst = match *kind {
                 AggregateKind::Array(..)
                 | AggregateKind::Tuple
@@ -886,13 +903,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
         }
 
-        let (ty, variant_index) = match *kind {
+        let (mut ty, variant_index) = match *kind {
             AggregateKind::Array(..) => {
-                assert!(!fields.is_empty());
+                assert!(!field_ops.is_empty());
                 (AggregateTy::Array, FIRST_VARIANT)
             }
             AggregateKind::Tuple => {
-                assert!(!fields.is_empty());
+                assert!(!field_ops.is_empty());
                 (AggregateTy::Tuple, FIRST_VARIANT)
             }
             AggregateKind::Closure(did, args)
@@ -903,15 +920,49 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             }
             // Do not track unions.
             AggregateKind::Adt(_, _, _, _, Some(_)) => return None,
-            // FIXME: Do the extra work to GVN `from_raw_parts`
-            AggregateKind::RawPtr(..) => return None,
+            AggregateKind::RawPtr(pointee_ty, mtbl) => {
+                assert_eq!(field_ops.len(), 2);
+                let data_pointer_ty = field_ops[FieldIdx::ZERO].ty(self.local_decls, self.tcx);
+                let output_pointer_ty = Ty::new_ptr(self.tcx, pointee_ty, mtbl);
+                (AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty }, FIRST_VARIANT)
+            }
         };
 
-        let fields: Option<Vec<_>> = fields
+        let fields: Option<Vec<_>> = field_ops
             .iter_mut()
             .map(|op| self.simplify_operand(op, location).or_else(|| self.new_opaque()))
             .collect();
-        let fields = fields?;
+        let mut fields = fields?;
+
+        if let AggregateTy::RawPtr { data_pointer_ty, output_pointer_ty } = &mut ty {
+            let mut was_updated = false;
+
+            // Any thin pointer of matching mutability is fine as the data pointer.
+            while let Value::Cast {
+                kind: CastKind::PtrToPtr,
+                value: cast_value,
+                from: cast_from,
+                to: _,
+            } = self.get(fields[0])
+                && let ty::RawPtr(from_pointee_ty, from_mtbl) = cast_from.kind()
+                && let ty::RawPtr(_, output_mtbl) = output_pointer_ty.kind()
+                && from_mtbl == output_mtbl
+                && from_pointee_ty.is_sized(self.tcx, self.param_env)
+            {
+                fields[0] = *cast_value;
+                *data_pointer_ty = *cast_from;
+                was_updated = true;
+            }
+
+            if was_updated {
+                if let Some(const_) = self.try_as_constant(fields[0]) {
+                    field_ops[FieldIdx::ZERO] = Operand::Constant(Box::new(const_));
+                } else if let Some(local) = self.try_as_local(fields[0], location) {
+                    field_ops[FieldIdx::ZERO] = Operand::Copy(Place::from(local));
+                    self.reused_locals.insert(local);
+                }
+            }
+        }
 
         if let AggregateTy::Array = ty
             && fields.len() > 4
@@ -943,6 +994,9 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             (UnOp::Not, Value::BinaryOp(BinOp::Ne, lhs, rhs)) => {
                 Value::BinaryOp(BinOp::Eq, *lhs, *rhs)
             }
+            (UnOp::PtrMetadata, Value::Aggregate(AggregateTy::RawPtr { .. }, _, fields)) => {
+                return Some(fields[1]);
+            }
             _ => return None,
         };
 
@@ -1094,6 +1148,23 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             return self.new_opaque();
         }
 
+        let mut was_updated = false;
+
+        // If that cast just casts away the metadata again,
+        if let PtrToPtr = kind
+            && let Value::Aggregate(AggregateTy::RawPtr { data_pointer_ty, .. }, _, fields) =
+                self.get(value)
+            && let ty::RawPtr(to_pointee, _) = to.kind()
+            && to_pointee.is_sized(self.tcx, self.param_env)
+        {
+            from = *data_pointer_ty;
+            value = fields[0];
+            was_updated = true;
+            if *data_pointer_ty == to {
+                return Some(fields[0]);
+            }
+        }
+
         if let PtrToPtr | PointerCoercion(MutToConstPointer) = kind
             && let Value::Cast { kind: inner_kind, value: inner_value, from: inner_from, to: _ } =
                 *self.get(value)
@@ -1102,9 +1173,13 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
             from = inner_from;
             value = inner_value;
             *kind = PtrToPtr;
+            was_updated = true;
             if inner_from == to {
                 return Some(inner_value);
             }
+        }
+
+        if was_updated {
             if let Some(const_) = self.try_as_constant(value) {
                 *operand = Operand::Constant(Box::new(const_));
             } else if let Some(local) = self.try_as_local(value, location) {
diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff
new file mode 100644
index 00000000000..6e5bdb16595
--- /dev/null
+++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-abort.diff
@@ -0,0 +1,60 @@
+- // MIR for `casts_before_aggregate_raw_ptr` before GVN
++ // MIR for `casts_before_aggregate_raw_ptr` after GVN
+  
+  fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] {
+      debug x => _1;
+      let mut _0: *const [u8];
+      let _2: *const [u8; 4];
+      let mut _3: *const u32;
+      let mut _5: *const [u8; 4];
+      let mut _7: *const u8;
+      let mut _8: *const ();
+      scope 1 {
+          debug x => _2;
+          let _4: *const u8;
+          scope 2 {
+              debug x => _4;
+              let _6: *const ();
+              scope 3 {
+                  debug x => _6;
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = _1;
+-         _2 = move _3 as *const [u8; 4] (PtrToPtr);
++         _2 = _1 as *const [u8; 4] (PtrToPtr);
+          StorageDead(_3);
+-         StorageLive(_4);
++         nop;
+          StorageLive(_5);
+          _5 = _2;
+-         _4 = move _5 as *const u8 (PtrToPtr);
++         _4 = _1 as *const u8 (PtrToPtr);
+          StorageDead(_5);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _4;
+-         _6 = move _7 as *const () (PtrToPtr);
++         _6 = _1 as *const () (PtrToPtr);
+          StorageDead(_7);
+          StorageLive(_8);
+          _8 = _6;
+-         _0 = *const [u8] from (move _8, const 4_usize);
++         _0 = *const [u8] from (_1, const 4_usize);
+          StorageDead(_8);
+-         StorageDead(_6);
+-         StorageDead(_4);
+-         StorageDead(_2);
++         nop;
++         nop;
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..6e5bdb16595
--- /dev/null
+++ b/tests/mir-opt/gvn.casts_before_aggregate_raw_ptr.GVN.panic-unwind.diff
@@ -0,0 +1,60 @@
+- // MIR for `casts_before_aggregate_raw_ptr` before GVN
++ // MIR for `casts_before_aggregate_raw_ptr` after GVN
+  
+  fn casts_before_aggregate_raw_ptr(_1: *const u32) -> *const [u8] {
+      debug x => _1;
+      let mut _0: *const [u8];
+      let _2: *const [u8; 4];
+      let mut _3: *const u32;
+      let mut _5: *const [u8; 4];
+      let mut _7: *const u8;
+      let mut _8: *const ();
+      scope 1 {
+          debug x => _2;
+          let _4: *const u8;
+          scope 2 {
+              debug x => _4;
+              let _6: *const ();
+              scope 3 {
+                  debug x => _6;
+              }
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = _1;
+-         _2 = move _3 as *const [u8; 4] (PtrToPtr);
++         _2 = _1 as *const [u8; 4] (PtrToPtr);
+          StorageDead(_3);
+-         StorageLive(_4);
++         nop;
+          StorageLive(_5);
+          _5 = _2;
+-         _4 = move _5 as *const u8 (PtrToPtr);
++         _4 = _1 as *const u8 (PtrToPtr);
+          StorageDead(_5);
+-         StorageLive(_6);
++         nop;
+          StorageLive(_7);
+          _7 = _4;
+-         _6 = move _7 as *const () (PtrToPtr);
++         _6 = _1 as *const () (PtrToPtr);
+          StorageDead(_7);
+          StorageLive(_8);
+          _8 = _6;
+-         _0 = *const [u8] from (move _8, const 4_usize);
++         _0 = *const [u8] from (_1, const 4_usize);
+          StorageDead(_8);
+-         StorageDead(_6);
+-         StorageDead(_4);
+-         StorageDead(_2);
++         nop;
++         nop;
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff
new file mode 100644
index 00000000000..73dbabb56b3
--- /dev/null
+++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-abort.diff
@@ -0,0 +1,32 @@
+- // MIR for `meta_of_ref_to_slice` before GVN
++ // MIR for `meta_of_ref_to_slice` after GVN
+  
+  fn meta_of_ref_to_slice(_1: *const i32) -> usize {
+      debug x => _1;
+      let mut _0: usize;
+      let _2: *const [i32];
+      let mut _3: *const i32;
+      let mut _4: *const [i32];
+      scope 1 {
+          debug ptr => _2;
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = _1;
+-         _2 = *const [i32] from (move _3, const 1_usize);
++         _2 = *const [i32] from (_1, const 1_usize);
+          StorageDead(_3);
+          StorageLive(_4);
+          _4 = _2;
+-         _0 = PtrMetadata(move _4);
++         _0 = const 1_usize;
+          StorageDead(_4);
+-         StorageDead(_2);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..73dbabb56b3
--- /dev/null
+++ b/tests/mir-opt/gvn.meta_of_ref_to_slice.GVN.panic-unwind.diff
@@ -0,0 +1,32 @@
+- // MIR for `meta_of_ref_to_slice` before GVN
++ // MIR for `meta_of_ref_to_slice` after GVN
+  
+  fn meta_of_ref_to_slice(_1: *const i32) -> usize {
+      debug x => _1;
+      let mut _0: usize;
+      let _2: *const [i32];
+      let mut _3: *const i32;
+      let mut _4: *const [i32];
+      scope 1 {
+          debug ptr => _2;
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = _1;
+-         _2 = *const [i32] from (move _3, const 1_usize);
++         _2 = *const [i32] from (_1, const 1_usize);
+          StorageDead(_3);
+          StorageLive(_4);
+          _4 = _2;
+-         _0 = PtrMetadata(move _4);
++         _0 = const 1_usize;
+          StorageDead(_4);
+-         StorageDead(_2);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.rs b/tests/mir-opt/gvn.rs
index 315377e4356..720018f112e 100644
--- a/tests/mir-opt/gvn.rs
+++ b/tests/mir-opt/gvn.rs
@@ -783,6 +783,39 @@ fn non_freeze<T: Copy>(x: T) {
     }
 }
 
+// Check that we can const-prop into `from_raw_parts`
+fn slice_const_length(x: &[i32]) -> *const [i32] {
+    // CHECK-LABEL: fn slice_const_length(
+    // CHECK: _0 = *const [i32] from ({{_[0-9]+}}, const 123_usize);
+    let ptr = x.as_ptr();
+    let len = 123;
+    std::intrinsics::aggregate_raw_ptr(ptr, len)
+}
+
+fn meta_of_ref_to_slice(x: *const i32) -> usize {
+    // CHECK-LABEL: fn meta_of_ref_to_slice
+    // CHECK: _0 = const 1_usize
+    let ptr: *const [i32] = std::intrinsics::aggregate_raw_ptr(x, 1);
+    std::intrinsics::ptr_metadata(ptr)
+}
+
+fn slice_from_raw_parts_as_ptr(x: *const u16, n: usize) -> (*const u16, *const f32) {
+    // CHECK-LABEL: fn slice_from_raw_parts_as_ptr
+    // CHECK: _8 = _1 as *const f32 (PtrToPtr);
+    // CHECK: _0 = (_1, move _8);
+    let ptr: *const [u16] = std::intrinsics::aggregate_raw_ptr(x, n);
+    (ptr as *const u16, ptr as *const f32)
+}
+
+fn casts_before_aggregate_raw_ptr(x: *const u32) -> *const [u8] {
+    // CHECK-LABEL: fn casts_before_aggregate_raw_ptr
+    // CHECK: _0 = *const [u8] from (_1, const 4_usize);
+    let x = x as *const [u8; 4];
+    let x = x as *const u8;
+    let x = x as *const ();
+    std::intrinsics::aggregate_raw_ptr(x, 4)
+}
+
 fn main() {
     subexpression_elimination(2, 4, 5);
     wrap_unwrap(5);
@@ -807,6 +840,9 @@ fn main() {
     wide_ptr_integer();
     borrowed(5);
     non_freeze(5);
+    slice_const_length(&[1]);
+    meta_of_ref_to_slice(&42);
+    slice_from_raw_parts_as_ptr(&123, 456);
 }
 
 #[inline(never)]
@@ -840,3 +876,7 @@ fn identity<T>(x: T) -> T {
 // EMIT_MIR gvn.wide_ptr_integer.GVN.diff
 // EMIT_MIR gvn.borrowed.GVN.diff
 // EMIT_MIR gvn.non_freeze.GVN.diff
+// EMIT_MIR gvn.slice_const_length.GVN.diff
+// EMIT_MIR gvn.meta_of_ref_to_slice.GVN.diff
+// EMIT_MIR gvn.slice_from_raw_parts_as_ptr.GVN.diff
+// EMIT_MIR gvn.casts_before_aggregate_raw_ptr.GVN.diff
diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff
new file mode 100644
index 00000000000..fd5fa035d81
--- /dev/null
+++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-abort.diff
@@ -0,0 +1,48 @@
+- // MIR for `slice_const_length` before GVN
++ // MIR for `slice_const_length` after GVN
+  
+  fn slice_const_length(_1: &[i32]) -> *const [i32] {
+      debug x => _1;
+      let mut _0: *const [i32];
+      let _2: *const i32;
+      let mut _3: &[i32];
+      let mut _5: *const i32;
+      let mut _6: usize;
+      scope 1 {
+          debug ptr => _2;
+          let _4: usize;
+          scope 2 {
+              debug len => _4;
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = &(*_1);
+          _2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind unreachable];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+-         StorageLive(_4);
++         nop;
+          _4 = const 123_usize;
+          StorageLive(_5);
+          _5 = _2;
+          StorageLive(_6);
+-         _6 = _4;
+-         _0 = *const [i32] from (move _5, move _6);
++         _6 = const 123_usize;
++         _0 = *const [i32] from (_2, const 123_usize);
+          StorageDead(_6);
+          StorageDead(_5);
+-         StorageDead(_4);
+-         StorageDead(_2);
++         nop;
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..98945cf9724
--- /dev/null
+++ b/tests/mir-opt/gvn.slice_const_length.GVN.panic-unwind.diff
@@ -0,0 +1,48 @@
+- // MIR for `slice_const_length` before GVN
++ // MIR for `slice_const_length` after GVN
+  
+  fn slice_const_length(_1: &[i32]) -> *const [i32] {
+      debug x => _1;
+      let mut _0: *const [i32];
+      let _2: *const i32;
+      let mut _3: &[i32];
+      let mut _5: *const i32;
+      let mut _6: usize;
+      scope 1 {
+          debug ptr => _2;
+          let _4: usize;
+          scope 2 {
+              debug len => _4;
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_2);
++         nop;
+          StorageLive(_3);
+          _3 = &(*_1);
+          _2 = core::slice::<impl [i32]>::as_ptr(move _3) -> [return: bb1, unwind continue];
+      }
+  
+      bb1: {
+          StorageDead(_3);
+-         StorageLive(_4);
++         nop;
+          _4 = const 123_usize;
+          StorageLive(_5);
+          _5 = _2;
+          StorageLive(_6);
+-         _6 = _4;
+-         _0 = *const [i32] from (move _5, move _6);
++         _6 = const 123_usize;
++         _0 = *const [i32] from (_2, const 123_usize);
+          StorageDead(_6);
+          StorageDead(_5);
+-         StorageDead(_4);
+-         StorageDead(_2);
++         nop;
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff
new file mode 100644
index 00000000000..75bcd2a8d72
--- /dev/null
+++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-abort.diff
@@ -0,0 +1,51 @@
+- // MIR for `slice_from_raw_parts_as_ptr` before GVN
++ // MIR for `slice_from_raw_parts_as_ptr` after GVN
+  
+  fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) {
+      debug x => _1;
+      debug n => _2;
+      let mut _0: (*const u16, *const f32);
+      let _3: *const [u16];
+      let mut _4: *const u16;
+      let mut _5: usize;
+      let mut _6: *const u16;
+      let mut _7: *const [u16];
+      let mut _8: *const f32;
+      let mut _9: *const [u16];
+      scope 1 {
+          debug ptr => _3;
+      }
+  
+      bb0: {
+-         StorageLive(_3);
++         nop;
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = *const [u16] from (move _4, move _5);
++         _3 = *const [u16] from (_1, _2);
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = _3;
+-         _6 = move _7 as *const u16 (PtrToPtr);
++         _6 = _1;
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = _3;
+-         _8 = move _9 as *const f32 (PtrToPtr);
++         _8 = _1 as *const f32 (PtrToPtr);
+          StorageDead(_9);
+-         _0 = (move _6, move _8);
++         _0 = (_1, move _8);
+          StorageDead(_8);
+          StorageDead(_6);
+-         StorageDead(_3);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff
new file mode 100644
index 00000000000..75bcd2a8d72
--- /dev/null
+++ b/tests/mir-opt/gvn.slice_from_raw_parts_as_ptr.GVN.panic-unwind.diff
@@ -0,0 +1,51 @@
+- // MIR for `slice_from_raw_parts_as_ptr` before GVN
++ // MIR for `slice_from_raw_parts_as_ptr` after GVN
+  
+  fn slice_from_raw_parts_as_ptr(_1: *const u16, _2: usize) -> (*const u16, *const f32) {
+      debug x => _1;
+      debug n => _2;
+      let mut _0: (*const u16, *const f32);
+      let _3: *const [u16];
+      let mut _4: *const u16;
+      let mut _5: usize;
+      let mut _6: *const u16;
+      let mut _7: *const [u16];
+      let mut _8: *const f32;
+      let mut _9: *const [u16];
+      scope 1 {
+          debug ptr => _3;
+      }
+  
+      bb0: {
+-         StorageLive(_3);
++         nop;
+          StorageLive(_4);
+          _4 = _1;
+          StorageLive(_5);
+          _5 = _2;
+-         _3 = *const [u16] from (move _4, move _5);
++         _3 = *const [u16] from (_1, _2);
+          StorageDead(_5);
+          StorageDead(_4);
+          StorageLive(_6);
+          StorageLive(_7);
+          _7 = _3;
+-         _6 = move _7 as *const u16 (PtrToPtr);
++         _6 = _1;
+          StorageDead(_7);
+          StorageLive(_8);
+          StorageLive(_9);
+          _9 = _3;
+-         _8 = move _9 as *const f32 (PtrToPtr);
++         _8 = _1 as *const f32 (PtrToPtr);
+          StorageDead(_9);
+-         _0 = (move _6, move _8);
++         _0 = (_1, move _8);
+          StorageDead(_8);
+          StorageDead(_6);
+-         StorageDead(_3);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
index 2c6d93e10c1..2f6139712ff 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir
@@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         scope 3 (inlined std::ptr::const_ptr::<impl *const u8>::add) {
         }
         scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
-            let mut _5: *const ();
-            let mut _6: usize;
+            let mut _5: usize;
             scope 5 (inlined std::ptr::metadata::<[u32]>) {
             }
             scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) {
@@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         _4 = Offset(_3, _2);
         StorageDead(_3);
         StorageLive(_5);
-        _5 = _4 as *const () (PtrToPtr);
-        StorageLive(_6);
-        _6 = PtrMetadata(_1);
-        _0 = *const [u32] from (_5, _6);
-        StorageDead(_6);
+        _5 = PtrMetadata(_1);
+        _0 = *const [u32] from (_4, _5);
         StorageDead(_5);
         StorageDead(_4);
         return;
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
index 2c6d93e10c1..2f6139712ff 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir
@@ -12,8 +12,7 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         scope 3 (inlined std::ptr::const_ptr::<impl *const u8>::add) {
         }
         scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) {
-            let mut _5: *const ();
-            let mut _6: usize;
+            let mut _5: usize;
             scope 5 (inlined std::ptr::metadata::<[u32]>) {
             }
             scope 6 (inlined std::ptr::from_raw_parts::<[u32], ()>) {
@@ -28,11 +27,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] {
         _4 = Offset(_3, _2);
         StorageDead(_3);
         StorageLive(_5);
-        _5 = _4 as *const () (PtrToPtr);
-        StorageLive(_6);
-        _6 = PtrMetadata(_1);
-        _0 = *const [u32] from (_5, _6);
-        StorageDead(_6);
+        _5 = PtrMetadata(_1);
+        _0 = *const [u32] from (_4, _5);
         StorageDead(_5);
         StorageDead(_4);
         return;
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir
index 04fb6b838f0..8d47e63eff2 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-abort.mir
@@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 {
     }
 
     bb0: {
+        StorageLive(_4);
         StorageLive(_3);
         _3 = _1 as *const u8 (PtrToPtr);
         _4 = Offset(_3, _2);
         StorageDead(_3);
         _0 = _4 as *const u32 (PtrToPtr);
+        StorageDead(_4);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir
index 04fb6b838f0..8d47e63eff2 100644
--- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_thin.PreCodegen.after.panic-unwind.mir
@@ -20,11 +20,13 @@ fn demo_byte_add_thin(_1: *const u32, _2: usize) -> *const u32 {
     }
 
     bb0: {
+        StorageLive(_4);
         StorageLive(_3);
         _3 = _1 as *const u8 (PtrToPtr);
         _4 = Offset(_3, _2);
         StorageDead(_3);
         _0 = _4 as *const u32 (PtrToPtr);
+        StorageDead(_4);
         return;
     }
 }