core_simd/simd/ptr/mut_ptr.rs
1use crate::simd::{Mask, Simd, cmp::SimdPartialEq, num::SimdUint};
2
3/// Operations on SIMD vectors of mutable pointers.
4pub impl(self) trait SimdMutPtr: 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 constant pointers to the same type.
15 type ConstPtr;
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_const`] on each element.
31 fn cast_const(self) -> Self::ConstPtr;
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_mut`] and returns the "address" portion.
45 ///
46 /// Equivalent to calling [`pointer::expose_provenance`] on each element.
47 ///
48 /// See [`super::with_exposed_provenance_mut`] 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> SimdMutPtr for Simd<*mut T, N> {
68 type Usize = Simd<usize, N>;
69 type Isize = Simd<isize, N>;
70 type CastPtr<U> = Simd<*mut U, N>;
71 type ConstPtr = Simd<*const T, N>;
72 type Mask = Mask<isize, N>;
73
74 #[inline]
75 fn is_null(self) -> Self::Mask {
76 Simd::splat(core::ptr::null_mut()).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_const(self) -> Self::ConstPtr {
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}