1
Fork 0

Auto merge of #110837 - scottmcm:offset-for-add, r=compiler-errors

Use MIR's `Offset` for pointer `add` too

~~Status: draft while waiting for #110822 to land, since this is built atop that.~~
~~r? `@ghost~~`

Canonical Rust code has mostly moved to `add`/`sub` on pointers, which take `usize`, instead of `offset` which takes `isize`.  (And, relatedly, when `sub_ptr` was added it turned out it replaced every single in-tree use of `offset_from`, because `usize` is just so much more useful than `isize` in Rust.)

Unfortunately, `intrinsics::offset` could only accept `*const` and `isize`, so there's a *huge* amount of type conversions back and forth being done.  They're identity conversions in the backend, but still end up producing quite a lot of unhelpful MIR.

This PR changes `intrinsics::offset` to accept `*const` *and* `*mut` along with `isize` *and* `usize`.  Conveniently, the backends and CTFE already handle this, since MIR's `BinOp::Offset` [already supports all four combinations](adaac6b166/compiler/rustc_const_eval/src/transform/validate.rs (L523-L528)).

To demonstrate the difference, I added some `mir-opt/pre-codegen/` tests around slice indexing.  Here's the difference to `[T]::get_mut`, since it uses `<*mut _>::add` internally:
```diff
`@@` -79,30 +70,21 `@@` fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> {
         StorageLive(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageLive(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         _9 = _8 as *mut u32 (PtrToPtr);  // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageLive(_13);                // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        _13 = _2 as isize (IntToInt);    // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageLive(_14);                // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageLive(_15);                // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        _15 = _9 as *const u32 (Pointer(MutToConstPointer)); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        _14 = Offset(move _15, _13);     // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageDead(_15);                // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        _7 = move _14 as *mut u32 (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageDead(_14);                // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
-        StorageDead(_13);                // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
+        _7 = Offset(_9, _2);             // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL
         StorageDead(_9);                 // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageDead(_12);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
         StorageDead(_11);                // scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL
```
https://github.com/rust-lang/rust/pull/110837/commits/1c1c8e442add0f46905a57a25a6cba52b8b0c54d#diff-a841b6a4538657add3f39bc895744331453d0625e7aace128b1f604f0b63c8fdR80
This commit is contained in:
bors 2023-04-28 09:26:59 +00:00
commit 43a78029b4
14 changed files with 401 additions and 13 deletions

View file

@ -1413,6 +1413,10 @@ extern "rust-intrinsic" {
/// This is implemented as an intrinsic to avoid converting to and from an
/// integer, since the conversion would throw away aliasing information.
///
/// This can only be used with `Ptr` as a raw pointer type (`*mut` or `*const`)
/// to a `Sized` pointee and with `Delta` as `usize` or `isize`. Any other
/// instantiations may arbitrarily misbehave, and that's *not* a compiler bug.
///
/// # Safety
///
/// Both the starting and resulting pointer must be either in bounds or one
@ -1421,6 +1425,14 @@ extern "rust-intrinsic" {
/// returned value will result in undefined behavior.
///
/// The stabilized version of this intrinsic is [`pointer::offset`].
#[cfg(not(bootstrap))]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_nounwind]
pub fn offset<Ptr, Delta>(dst: Ptr, offset: Delta) -> Ptr;
/// The bootstrap version of this is more restricted.
#[cfg(bootstrap)]
#[must_use = "returns a new pointer rather than modifying its argument"]
#[rustc_const_stable(feature = "const_ptr_offset", since = "1.61.0")]
#[rustc_nounwind]

View file

@ -916,8 +916,16 @@ impl<T: ?Sized> *const T {
where
T: Sized,
{
#[cfg(bootstrap)]
// SAFETY: the caller must uphold the safety contract for `offset`.
unsafe { self.offset(count as isize) }
unsafe {
self.offset(count as isize)
}
#[cfg(not(bootstrap))]
// SAFETY: the caller must uphold the safety contract for `offset`.
unsafe {
intrinsics::offset(self, count)
}
}
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).

View file

@ -473,10 +473,20 @@ impl<T: ?Sized> *mut T {
where
T: Sized,
{
#[cfg(bootstrap)]
// SAFETY: the caller must uphold the safety contract for `offset`.
// The obtained pointer is valid for writes since the caller must
// guarantee that it points to the same allocated object as `self`.
unsafe { intrinsics::offset(self, count) as *mut T }
unsafe {
intrinsics::offset(self, count) as *mut T
}
#[cfg(not(bootstrap))]
// SAFETY: the caller must uphold the safety contract for `offset`.
// The obtained pointer is valid for writes since the caller must
// guarantee that it points to the same allocated object as `self`.
unsafe {
intrinsics::offset(self, count)
}
}
/// Calculates the offset from a pointer in bytes.
@ -1016,8 +1026,16 @@ impl<T: ?Sized> *mut T {
where
T: Sized,
{
#[cfg(bootstrap)]
// SAFETY: the caller must uphold the safety contract for `offset`.
unsafe { self.offset(count as isize) }
unsafe {
self.offset(count as isize)
}
#[cfg(not(bootstrap))]
// SAFETY: the caller must uphold the safety contract for `offset`.
unsafe {
intrinsics::offset(self, count)
}
}
/// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`).