core/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
use super::sealed::Sealed;
use crate::simd::{cmp::SimdPartialEq, num::SimdUint, LaneCount, Mask, Simd, SupportedLaneCount};
/// Operations on SIMD vectors of mutable pointers.
pub trait SimdMutPtr: Copy Sealed {
/// Vector of `usize` with the same number of elements.
type Usize;
/// Vector of `isize` with the same number of elements.
type Isize;
/// Vector of const pointers with the same number of elements.
type CastPtr<T>;
/// Vector of constant pointers to the same type.
type ConstPtr;
/// Mask type used for manipulating this SIMD vector type.
type Mask;
/// Returns `true` for each element that is null.
fn is_null(self) -> Self::Mask;
/// Casts to a pointer of another type.
///
/// Equivalent to calling [`pointer::cast`] on each element.
fn cast<T>(self) -> Self::CastPtr<T>;
/// Changes constness without changing the type.
///
/// Equivalent to calling [`pointer::cast_const`] on each element.
fn cast_const(self) -> Self::ConstPtr;
/// Gets the "address" portion of the pointer.
///
/// This method discards pointer semantic metadata, so the result cannot be
/// directly cast into a valid pointer.
///
/// Equivalent to calling [`pointer::addr`] on each element.
fn addr(self) -> Self::Usize;
/// Creates a new pointer with the given address.
///
/// This performs the same operation as a cast, but copies the *address-space* and
/// *provenance* of `self` to the new pointer.
///
/// Equivalent to calling [`pointer::with_addr`] on each element.
fn with_addr(self, addr: Self::Usize) -> Self;
/// Exposes the "provenance" part of the pointer for future use in
/// [`Self::with_exposed_provenance`] and returns the "address" portion.
fn expose_provenance(self) -> Self::Usize;
/// Converts an address back to a pointer, picking up a previously "exposed" provenance.
///
/// Equivalent to calling [`core::ptr::with_exposed_provenance_mut`] on each element.
fn with_exposed_provenance(addr: Self::Usize) -> Self;
/// Calculates the offset from a pointer using wrapping arithmetic.
///
/// Equivalent to calling [`pointer::wrapping_offset`] on each element.
fn wrapping_offset(self, offset: Self::Isize) -> Self;
/// Calculates the offset from a pointer using wrapping arithmetic.
///
/// Equivalent to calling [`pointer::wrapping_add`] on each element.
fn wrapping_add(self, count: Self::Usize) -> Self;
/// Calculates the offset from a pointer using wrapping arithmetic.
///
/// Equivalent to calling [`pointer::wrapping_sub`] on each element.
fn wrapping_sub(self, count: Self::Usize) -> Self;
}
impl<T, const N: usize> Sealed for Simd<*mut T, N> where LaneCount<N>: SupportedLaneCount {}
impl<T, const N: usize> SimdMutPtr for Simd<*mut T, N>
where
LaneCount<N>: SupportedLaneCount,
{
type Usize = Simd<usize, N>;
type Isize = Simd<isize, N>;
type CastPtr<U> = Simd<*mut U, N>;
type ConstPtr = Simd<*const T, N>;
type Mask = Mask<isize, N>;
#[inline]
fn is_null(self) -> Self::Mask {
Simd::splat(core::ptr::null_mut()).simd_eq(self)
}
#[inline]
fn cast<U>(self) -> Self::CastPtr<U> {
// SimdElement currently requires zero-sized metadata, so this should never fail.
// If this ever changes, `simd_cast_ptr` should produce a post-mono error.
use core::ptr::Pointee;
assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0);
assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
// Safety: pointers can be cast
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
}
#[inline]
fn cast_const(self) -> Self::ConstPtr {
// Safety: pointers can be cast
unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
}
#[inline]
fn addr(self) -> Self::Usize {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
// SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
// provenance).
unsafe { core::mem::transmute_copy(&self) }
}
#[inline]
fn with_addr(self, addr: Self::Usize) -> Self {
// FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
//
// In the mean-time, this operation is defined to be "as if" it was
// a wrapping_offset, so we can emulate it as such. This should properly
// restore pointer provenance even under today's compiler.
self.cast::<u8>()
.wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
.cast()
}
#[inline]
fn expose_provenance(self) -> Self::Usize {
// Safety: `self` is a pointer vector
unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
}
#[inline]
fn with_exposed_provenance(addr: Self::Usize) -> Self {
// Safety: `self` is a pointer vector
unsafe { core::intrinsics::simd::simd_with_exposed_provenance(addr) }
}
#[inline]
fn wrapping_offset(self, count: Self::Isize) -> Self {
// Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
}
#[inline]
fn wrapping_add(self, count: Self::Usize) -> Self {
self.wrapping_offset(count.cast())
}
#[inline]
fn wrapping_sub(self, count: Self::Usize) -> Self {
self.wrapping_offset(-count.cast::<isize>())
}
}