Skip to main content

core_simd/simd/ptr/
mut_ptr.rs

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