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 /// Equivalent to calling [`pointer::addr`] on each element.
37 fn addr(self) -> Self::Usize;
38
39 /// Creates a new pointer with the given address.
40 ///
41 /// Equivalent to calling [`pointer::with_addr`] on each element.
42 fn with_addr(self, addr: Self::Usize) -> Self;
43
44 /// Exposes the "provenance" part of the pointer for future use in
45 /// [`super::with_exposed_provenance`] and returns the "address" portion.
46 ///
47 /// Equivalent to calling [`pointer::expose_provenance`] on each element.
48 ///
49 /// See [`super::with_exposed_provenance`] for the matching constructor.
50 fn expose_provenance(self) -> Self::Usize;
51
52 /// Calculates the offset from a pointer using wrapping arithmetic.
53 ///
54 /// Equivalent to calling [`pointer::wrapping_offset`] on each element.
55 fn wrapping_offset(self, offset: Self::Isize) -> Self;
56
57 /// Calculates the offset from a pointer using wrapping arithmetic.
58 ///
59 /// Equivalent to calling [`pointer::wrapping_add`] on each element.
60 fn wrapping_add(self, count: Self::Usize) -> Self;
61
62 /// Calculates the offset from a pointer using wrapping arithmetic.
63 ///
64 /// Equivalent to calling [`pointer::wrapping_sub`] on each element.
65 fn wrapping_sub(self, count: Self::Usize) -> Self;
66}
67
68impl<T, const N: usize> Sealed for Simd<*const T, N> {}
69
70impl<T, const N: usize> SimdConstPtr for Simd<*const T, N> {
71 type Usize = Simd<usize, N>;
72 type Isize = Simd<isize, N>;
73 type CastPtr<U> = Simd<*const U, N>;
74 type MutPtr = Simd<*mut T, N>;
75 type Mask = Mask<isize, N>;
76
77 #[inline]
78 fn is_null(self) -> Self::Mask {
79 Simd::splat(core::ptr::null()).simd_eq(self)
80 }
81
82 #[inline]
83 fn cast<U>(self) -> Self::CastPtr<U> {
84 // SimdElement currently requires zero-sized metadata, so this should never fail.
85 // If this ever changes, `simd_cast_ptr` should produce a post-mono error.
86 use core::ptr::Pointee;
87 assert_eq!(size_of::<<T as Pointee>::Metadata>(), 0);
88 assert_eq!(size_of::<<U as Pointee>::Metadata>(), 0);
89
90 // Safety: pointers can be cast
91 unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
92 }
93
94 #[inline]
95 fn cast_mut(self) -> Self::MutPtr {
96 // Safety: pointers can be cast
97 unsafe { core::intrinsics::simd::simd_cast_ptr(self) }
98 }
99
100 #[inline]
101 fn addr(self) -> Self::Usize {
102 // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
103 // SAFETY: Pointer-to-integer transmutes are valid (if you are okay with losing the
104 // provenance).
105 unsafe { core::mem::transmute_copy(&self) }
106 }
107
108 #[inline]
109 fn with_addr(self, addr: Self::Usize) -> Self {
110 // FIXME(strict_provenance_magic): I am magic and should be a compiler intrinsic.
111 //
112 // In the mean-time, this operation is defined to be "as if" it was
113 // a wrapping_offset, so we can emulate it as such. This should properly
114 // restore pointer provenance even under today's compiler.
115 self.cast::<u8>()
116 .wrapping_offset(addr.cast::<isize>() - self.addr().cast::<isize>())
117 .cast()
118 }
119
120 #[inline]
121 fn expose_provenance(self) -> Self::Usize {
122 // Safety: `self` is a pointer vector
123 unsafe { core::intrinsics::simd::simd_expose_provenance(self) }
124 }
125
126 #[inline]
127 fn wrapping_offset(self, count: Self::Isize) -> Self {
128 // Safety: simd_arith_offset takes a vector of pointers and a vector of offsets
129 unsafe { core::intrinsics::simd::simd_arith_offset(self, count) }
130 }
131
132 #[inline]
133 fn wrapping_add(self, count: Self::Usize) -> Self {
134 self.wrapping_offset(count.cast())
135 }
136
137 #[inline]
138 fn wrapping_sub(self, count: Self::Usize) -> Self {
139 self.wrapping_offset(-count.cast::<isize>())
140 }
141}