core/portable-simd/crates/core_simd/src/simd/num/
uint.rs

1use super::sealed::Sealed;
2use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd};
3
4/// Operations on SIMD vectors of unsigned integers.
5pub trait SimdUint: Copy + Sealed {
6    /// Scalar type contained by this SIMD vector type.
7    type Scalar;
8
9    /// A SIMD vector with a different element type.
10    type Cast<T: SimdElement>;
11
12    /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
13    ///
14    /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
15    /// other integer types, and saturating to float types).
16    #[must_use]
17    fn cast<T: SimdCast>(self) -> Self::Cast<T>;
18
19    /// Wrapping negation.
20    ///
21    /// Like [`u32::wrapping_neg`], all applications of this function will wrap, with the exception
22    /// of `-0`.
23    fn wrapping_neg(self) -> Self;
24
25    /// Lanewise saturating add.
26    ///
27    /// # Examples
28    /// ```
29    /// # #![feature(portable_simd)]
30    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
31    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
32    /// # use simd::prelude::*;
33    /// use core::u32::MAX;
34    /// let x = Simd::from_array([2, 1, 0, MAX]);
35    /// let max = Simd::splat(MAX);
36    /// let unsat = x + max;
37    /// let sat = x.saturating_add(max);
38    /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
39    /// assert_eq!(sat, max);
40    /// ```
41    fn saturating_add(self, second: Self) -> Self;
42
43    /// Lanewise saturating subtract.
44    ///
45    /// # Examples
46    /// ```
47    /// # #![feature(portable_simd)]
48    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
49    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
50    /// # use simd::prelude::*;
51    /// use core::u32::MAX;
52    /// let x = Simd::from_array([2, 1, 0, MAX]);
53    /// let max = Simd::splat(MAX);
54    /// let unsat = x - max;
55    /// let sat = x.saturating_sub(max);
56    /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
57    /// assert_eq!(sat, Simd::splat(0));
58    /// ```
59    fn saturating_sub(self, second: Self) -> Self;
60
61    /// Lanewise absolute difference.
62    /// Every element becomes the absolute difference of `self` and `second`.
63    ///
64    /// # Examples
65    /// ```
66    /// # #![feature(portable_simd)]
67    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
68    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
69    /// # use simd::prelude::*;
70    /// use core::u32::MAX;
71    /// let a = Simd::from_array([0, MAX, 100, 20]);
72    /// let b = Simd::from_array([MAX, 0, 80, 200]);
73    /// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
74    /// ```
75    fn abs_diff(self, second: Self) -> Self;
76
77    /// Returns the sum of the elements of the vector, with wrapping addition.
78    fn reduce_sum(self) -> Self::Scalar;
79
80    /// Returns the product of the elements of the vector, with wrapping multiplication.
81    fn reduce_product(self) -> Self::Scalar;
82
83    /// Returns the maximum element in the vector.
84    fn reduce_max(self) -> Self::Scalar;
85
86    /// Returns the minimum element in the vector.
87    fn reduce_min(self) -> Self::Scalar;
88
89    /// Returns the cumulative bitwise "and" across the elements of the vector.
90    fn reduce_and(self) -> Self::Scalar;
91
92    /// Returns the cumulative bitwise "or" across the elements of the vector.
93    fn reduce_or(self) -> Self::Scalar;
94
95    /// Returns the cumulative bitwise "xor" across the elements of the vector.
96    fn reduce_xor(self) -> Self::Scalar;
97
98    /// Reverses the byte order of each element.
99    fn swap_bytes(self) -> Self;
100
101    /// Reverses the order of bits in each elemnent.
102    /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
103    fn reverse_bits(self) -> Self;
104
105    /// Returns the number of ones in the binary representation of each element.
106    fn count_ones(self) -> Self;
107
108    /// Returns the number of zeros in the binary representation of each element.
109    fn count_zeros(self) -> Self;
110
111    /// Returns the number of leading zeros in the binary representation of each element.
112    fn leading_zeros(self) -> Self;
113
114    /// Returns the number of trailing zeros in the binary representation of each element.
115    fn trailing_zeros(self) -> Self;
116
117    /// Returns the number of leading ones in the binary representation of each element.
118    fn leading_ones(self) -> Self;
119
120    /// Returns the number of trailing ones in the binary representation of each element.
121    fn trailing_ones(self) -> Self;
122}
123
124macro_rules! impl_trait {
125    { $($ty:ident ($signed:ident)),* } => {
126        $(
127        impl<const N: usize> Sealed for Simd<$ty, N>
128        where
129            LaneCount<N>: SupportedLaneCount,
130        {
131        }
132
133        impl<const N: usize> SimdUint for Simd<$ty, N>
134        where
135            LaneCount<N>: SupportedLaneCount,
136        {
137            type Scalar = $ty;
138            type Cast<T: SimdElement> = Simd<T, N>;
139
140            #[inline]
141            fn cast<T: SimdCast>(self) -> Self::Cast<T> {
142                // Safety: supported types are guaranteed by SimdCast
143                unsafe { core::intrinsics::simd::simd_as(self) }
144            }
145
146            #[inline]
147            fn wrapping_neg(self) -> Self {
148                use crate::simd::num::SimdInt;
149                (-self.cast::<$signed>()).cast()
150            }
151
152            #[inline]
153            fn saturating_add(self, second: Self) -> Self {
154                // Safety: `self` is a vector
155                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
156            }
157
158            #[inline]
159            fn saturating_sub(self, second: Self) -> Self {
160                // Safety: `self` is a vector
161                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
162            }
163
164            #[inline]
165            fn abs_diff(self, second: Self) -> Self {
166                let max = self.simd_max(second);
167                let min = self.simd_min(second);
168                max - min
169            }
170
171            #[inline]
172            fn reduce_sum(self) -> Self::Scalar {
173                // Safety: `self` is an integer vector
174                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
175            }
176
177            #[inline]
178            fn reduce_product(self) -> Self::Scalar {
179                // Safety: `self` is an integer vector
180                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
181            }
182
183            #[inline]
184            fn reduce_max(self) -> Self::Scalar {
185                // Safety: `self` is an integer vector
186                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
187            }
188
189            #[inline]
190            fn reduce_min(self) -> Self::Scalar {
191                // Safety: `self` is an integer vector
192                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
193            }
194
195            #[inline]
196            fn reduce_and(self) -> Self::Scalar {
197                // Safety: `self` is an integer vector
198                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
199            }
200
201            #[inline]
202            fn reduce_or(self) -> Self::Scalar {
203                // Safety: `self` is an integer vector
204                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
205            }
206
207            #[inline]
208            fn reduce_xor(self) -> Self::Scalar {
209                // Safety: `self` is an integer vector
210                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
211            }
212
213            #[inline]
214            fn swap_bytes(self) -> Self {
215                // Safety: `self` is an integer vector
216                unsafe { core::intrinsics::simd::simd_bswap(self) }
217            }
218
219            #[inline]
220            fn reverse_bits(self) -> Self {
221                // Safety: `self` is an integer vector
222                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
223            }
224
225            #[inline]
226            fn count_ones(self) -> Self {
227                // Safety: `self` is an integer vector
228                unsafe { core::intrinsics::simd::simd_ctpop(self) }
229            }
230
231            #[inline]
232            fn count_zeros(self) -> Self {
233                (!self).count_ones()
234            }
235
236            #[inline]
237            fn leading_zeros(self) -> Self {
238                // Safety: `self` is an integer vector
239                unsafe { core::intrinsics::simd::simd_ctlz(self) }
240            }
241
242            #[inline]
243            fn trailing_zeros(self) -> Self {
244                // Safety: `self` is an integer vector
245                unsafe { core::intrinsics::simd::simd_cttz(self) }
246            }
247
248            #[inline]
249            fn leading_ones(self) -> Self {
250                (!self).leading_zeros()
251            }
252
253            #[inline]
254            fn trailing_ones(self) -> Self {
255                (!self).trailing_zeros()
256            }
257        }
258        )*
259    }
260}
261
262impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) }