Skip to main content

core_simd/simd/ptr/
const_ptr.rs

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