Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Shrink from_raw_parts's MIR so that Vec::deref MIR-inlines again #123190

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 74 additions & 0 deletions library/core/src/ptr/internal_repr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//! This encapsulates the layout knowledge for pointers, only exporting the two
//! safe functions that can be used to interact with the metadata directly.

use super::{NonNull, Pointee, Thin};

#[inline]
pub(super) const fn metadata<P: RawPointer>(ptr: P) -> <P::Pointee as Pointee>::Metadata {
// SAFETY: Transmuting like this is safe since `P` and `PtrComponents`
// have the same memory layouts. Only std can make this guarantee.
unsafe {
crate::intrinsics::transmute_unchecked::<
P,
PtrComponents<P::Family, <P::Pointee as Pointee>::Metadata>,
>(ptr)
.metadata
}
}

/// Just like [`super::from_raw_parts`] and [`super::from_raw_parts_mut`], but
/// more flexible in terms of which types it can take, allowing smaller MIR.
// See <https://github.com/rust-lang/rust/issues/123174>
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub(super) const fn from_raw_parts<P: RawPointer>(
data_pointer: impl RawPointer<Pointee: Thin, Family = P::Family>,
metadata: <P::Pointee as Pointee>::Metadata,
) -> P {
// SAFETY: Transmuting like this is safe since `P` and `PtrComponents`
// have the same memory layouts. Only std can make this guarantee.
unsafe {
crate::intrinsics::transmute_unchecked::<
PtrComponents<_, <P::Pointee as Pointee>::Metadata>,
P,
>(PtrComponents { data_pointer, metadata })
}
}

// Intentionally private with no derives, as it's only used via transmuting.
// This layout is not stable; only std can rely on it.
// (And should only do so in the two functions in this module.)
#[repr(C)]
struct PtrComponents<P, M = ()> {
data_pointer: P,
metadata: M,
}

/// Internal trait to avoid bad instantiations of [`PtrComponents`]
///
/// # Safety
///
/// Must have the same layout as `*const Self::Pointee` and be able to hold provenance.
///
/// Every type with the same associated `Family` must be soundly transmutable
/// between each other when the metadata is the same.
pub unsafe trait RawPointer: Copy {
type Pointee: ?Sized + super::Pointee;
type Family: RawPointer<Pointee = (), Family = Self::Family>;
}

// SAFETY: `*const T` is obviously a raw pointer
unsafe impl<T: ?Sized> RawPointer for *const T {
type Pointee = T;
type Family = *const ();
}
// SAFETY: `*mut T` is obviously a raw pointer
unsafe impl<T: ?Sized> RawPointer for *mut T {
type Pointee = T;
type Family = *mut ();
}
// SAFETY: `NonNull<T>` is a transparent newtype around a `*const T`.
unsafe impl<T: ?Sized> RawPointer for NonNull<T> {
type Pointee = T;
type Family = NonNull<()>;
}
39 changes: 4 additions & 35 deletions library/core/src/ptr/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::ptr::internal_repr;

/// Provides the pointer metadata type of any pointed-to type.
///
Expand Down Expand Up @@ -92,10 +93,7 @@ pub trait Thin = Pointee<Metadata = ()>;
#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")]
#[inline]
pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
// and PtrComponents<T> have the same memory layouts. Only std can make this
// guarantee.
unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
internal_repr::metadata(ptr)
}

/// Forms a (possibly-wide) raw pointer from a data pointer and metadata.
Expand All @@ -112,10 +110,7 @@ pub const fn from_raw_parts<T: ?Sized>(
data_pointer: *const (),
metadata: <T as Pointee>::Metadata,
) -> *const T {
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
// and PtrComponents<T> have the same memory layouts. Only std can make this
// guarantee.
unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.const_ptr }
internal_repr::from_raw_parts(data_pointer, metadata)
}

/// Performs the same functionality as [`from_raw_parts`], except that a
Expand All @@ -129,33 +124,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>(
data_pointer: *mut (),
metadata: <T as Pointee>::Metadata,
) -> *mut T {
// SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T
// and PtrComponents<T> have the same memory layouts. Only std can make this
// guarantee.
unsafe { PtrRepr { components: PtrComponents { data_pointer, metadata } }.mut_ptr }
}

#[repr(C)]
union PtrRepr<T: ?Sized> {
const_ptr: *const T,
mut_ptr: *mut T,
components: PtrComponents<T>,
}

#[repr(C)]
struct PtrComponents<T: ?Sized> {
data_pointer: *const (),
metadata: <T as Pointee>::Metadata,
}

// Manual impl needed to avoid `T: Copy` bound.
impl<T: ?Sized> Copy for PtrComponents<T> {}

// Manual impl needed to avoid `T: Clone` bound.
impl<T: ?Sized> Clone for PtrComponents<T> {
fn clone(&self) -> Self {
*self
}
internal_repr::from_raw_parts(data_pointer, metadata)
}

/// The metadata for a `Dyn = dyn SomeTrait` trait object type.
Expand Down
6 changes: 4 additions & 2 deletions library/core/src/ptr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,8 @@ pub use crate::intrinsics::copy;
#[doc(inline)]
pub use crate::intrinsics::write_bytes;

mod internal_repr;

mod metadata;
#[unstable(feature = "ptr_metadata", issue = "81513")]
pub use metadata::{from_raw_parts, from_raw_parts_mut, metadata, DynMetadata, Pointee, Thin};
Expand Down Expand Up @@ -812,7 +814,7 @@ pub const fn from_mut<T: ?Sized>(r: &mut T) -> *mut T {
#[rustc_allow_const_fn_unstable(ptr_metadata)]
#[rustc_diagnostic_item = "ptr_slice_from_raw_parts"]
pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
from_raw_parts(data.cast(), len)
internal_repr::from_raw_parts(data, len)
}

/// Forms a raw mutable slice from a pointer and a length.
Expand Down Expand Up @@ -858,7 +860,7 @@ pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
#[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
#[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"]
pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
from_raw_parts_mut(data.cast(), len)
internal_repr::from_raw_parts(data, len)
}

/// Swaps the values at two mutable locations of the same type, without
Expand Down
8 changes: 2 additions & 6 deletions library/core/src/ptr/non_null.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ use crate::marker::Unsize;
use crate::mem::{MaybeUninit, SizedTypeProperties};
use crate::num::NonZero;
use crate::ops::{CoerceUnsized, DispatchFromDyn};
use crate::ptr;
use crate::ptr::Unique;
use crate::ptr::{self, internal_repr, Unique};
use crate::slice::{self, SliceIndex};
use crate::ub_checks::assert_unsafe_precondition;

Expand Down Expand Up @@ -265,10 +264,7 @@ impl<T: ?Sized> NonNull<T> {
data_pointer: NonNull<()>,
metadata: <T as super::Pointee>::Metadata,
) -> NonNull<T> {
// SAFETY: The result of `ptr::from::raw_parts_mut` is non-null because `data_pointer` is.
unsafe {
NonNull::new_unchecked(super::from_raw_parts_mut(data_pointer.as_ptr(), metadata))
}
internal_repr::from_raw_parts(data_pointer, metadata)
}

/// Decompose a (possibly wide) pointer into its data pointer and metadata components.
Expand Down
13 changes: 13 additions & 0 deletions tests/mir-opt/pre-codegen/vec_deref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// skip-filecheck
//@ compile-flags: -O -Zmir-opt-level=2 -Cdebuginfo=2
// EMIT_MIR_FOR_EACH_PANIC_STRATEGY

#![crate_type = "lib"]

// Added after it stopped inlining in a nightly; see
// <https://github.com/rust-lang/rust/issues/123174>

// EMIT_MIR vec_deref.vec_deref_to_slice.PreCodegen.after.mir
pub fn vec_deref_to_slice(v: &Vec<u8>) -> &[u8] {
v
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// MIR for `vec_deref_to_slice` after PreCodegen

fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
debug v => _1;
let mut _0: &[u8];
scope 1 (inlined <Vec<u8> as Deref>::deref) {
debug self => _1;
let mut _4: *const u8;
let mut _5: usize;
scope 2 {
scope 3 (inlined Vec::<u8>::as_ptr) {
debug self => _1;
let mut _2: &alloc::raw_vec::RawVec<u8>;
scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
debug self => _2;
let mut _3: std::ptr::NonNull<u8>;
scope 5 (inlined Unique::<u8>::as_ptr) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 6 (inlined NonNull::<u8>::as_ptr) {
debug self => _3;
}
}
}
}
scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _4;
debug len => _5;
let _7: *const [u8];
scope 8 {
scope 9 (inlined core::ub_checks::check_language_ub) {
scope 10 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
scope 11 (inlined std::mem::size_of::<u8>) {
}
scope 12 (inlined align_of::<u8>) {
}
scope 13 (inlined slice_from_raw_parts::<u8>) {
debug data => _4;
debug len => _5;
scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) {
debug data_pointer => _4;
debug metadata => _5;
let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>;
scope 15 {
}
}
}
}
}
}
}

bb0: {
StorageLive(_4);
StorageLive(_2);
_2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
StorageLive(_3);
_3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
_4 = (_3.0: *const u8);
StorageDead(_3);
StorageDead(_2);
StorageLive(_5);
_5 = ((*_1).1: usize);
StorageLive(_6);
_6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 };
_7 = move _6 as *const [u8] (Transmute);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
_0 = &(*_7);
return;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// MIR for `vec_deref_to_slice` after PreCodegen

fn vec_deref_to_slice(_1: &Vec<u8>) -> &[u8] {
debug v => _1;
let mut _0: &[u8];
scope 1 (inlined <Vec<u8> as Deref>::deref) {
debug self => _1;
let mut _4: *const u8;
let mut _5: usize;
scope 2 {
scope 3 (inlined Vec::<u8>::as_ptr) {
debug self => _1;
let mut _2: &alloc::raw_vec::RawVec<u8>;
scope 4 (inlined alloc::raw_vec::RawVec::<u8>::ptr) {
debug self => _2;
let mut _3: std::ptr::NonNull<u8>;
scope 5 (inlined Unique::<u8>::as_ptr) {
debug ((self: Unique<u8>).0: std::ptr::NonNull<u8>) => _3;
debug ((self: Unique<u8>).1: std::marker::PhantomData<u8>) => const PhantomData::<u8>;
scope 6 (inlined NonNull::<u8>::as_ptr) {
debug self => _3;
}
}
}
}
scope 7 (inlined std::slice::from_raw_parts::<'_, u8>) {
debug data => _4;
debug len => _5;
let _7: *const [u8];
scope 8 {
scope 9 (inlined core::ub_checks::check_language_ub) {
scope 10 (inlined core::ub_checks::check_language_ub::runtime) {
}
}
scope 11 (inlined std::mem::size_of::<u8>) {
}
scope 12 (inlined align_of::<u8>) {
}
scope 13 (inlined slice_from_raw_parts::<u8>) {
debug data => _4;
debug len => _5;
scope 14 (inlined std::ptr::internal_repr::from_raw_parts::<*const [u8], *const u8>) {
debug data_pointer => _4;
debug metadata => _5;
let mut _6: std::ptr::internal_repr::PtrComponents<*const u8, usize>;
scope 15 {
}
}
}
}
}
}
}

bb0: {
StorageLive(_4);
StorageLive(_2);
_2 = &((*_1).0: alloc::raw_vec::RawVec<u8>);
StorageLive(_3);
_3 = ((((*_1).0: alloc::raw_vec::RawVec<u8>).0: std::ptr::Unique<u8>).0: std::ptr::NonNull<u8>);
_4 = (_3.0: *const u8);
StorageDead(_3);
StorageDead(_2);
StorageLive(_5);
_5 = ((*_1).1: usize);
StorageLive(_6);
_6 = std::ptr::internal_repr::PtrComponents::<*const u8, usize> { data_pointer: _4, metadata: _5 };
_7 = move _6 as *const [u8] (Transmute);
StorageDead(_6);
StorageDead(_5);
StorageDead(_4);
_0 = &(*_7);
return;
}
}
Loading