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