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

1use super::sealed::Sealed;
2use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
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    fn saturating_sub(self, second: Self) -> Self;
59
60    /// Lanewise absolute difference.
61    /// Every element becomes the absolute difference of `self` and `second`.
62    ///
63    /// # Examples
64    /// ```
65    /// # #![feature(portable_simd)]
66    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
67    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
68    /// # use simd::prelude::*;
69    /// use core::u32::MAX;
70    /// let a = Simd::from_array([0, MAX, 100, 20]);
71    /// let b = Simd::from_array([MAX, 0, 80, 200]);
72    /// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
73    /// ```
74    fn abs_diff(self, second: Self) -> Self;
75
76    /// Returns the sum of the elements of the vector, with wrapping addition.
77    fn reduce_sum(self) -> Self::Scalar;
78
79    /// Returns the product of the elements of the vector, with wrapping multiplication.
80    fn reduce_product(self) -> Self::Scalar;
81
82    /// Returns the maximum element in the vector.
83    fn reduce_max(self) -> Self::Scalar;
84
85    /// Returns the minimum element in the vector.
86    fn reduce_min(self) -> Self::Scalar;
87
88    /// Returns the cumulative bitwise "and" across the elements of the vector.
89    fn reduce_and(self) -> Self::Scalar;
90
91    /// Returns the cumulative bitwise "or" across the elements of the vector.
92    fn reduce_or(self) -> Self::Scalar;
93
94    /// Returns the cumulative bitwise "xor" across the elements of the vector.
95    fn reduce_xor(self) -> Self::Scalar;
96
97    /// Reverses the byte order of each element.
98    fn swap_bytes(self) -> Self;
99
100    /// Reverses the order of bits in each elemnent.
101    /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
102    fn reverse_bits(self) -> Self;
103
104    /// Returns the number of ones in the binary representation of each element.
105    fn count_ones(self) -> Self;
106
107    /// Returns the number of zeros in the binary representation of each element.
108    fn count_zeros(self) -> Self;
109
110    /// Returns the number of leading zeros in the binary representation of each element.
111    fn leading_zeros(self) -> Self;
112
113    /// Returns the number of trailing zeros in the binary representation of each element.
114    fn trailing_zeros(self) -> Self;
115
116    /// Returns the number of leading ones in the binary representation of each element.
117    fn leading_ones(self) -> Self;
118
119    /// Returns the number of trailing ones in the binary representation of each element.
120    fn trailing_ones(self) -> Self;
121}
122
123macro_rules! impl_trait {
124    { $($ty:ident ($signed:ident)),* } => {
125        $(
126        impl<const N: usize> Sealed for Simd<$ty, N>
127        where
128            LaneCount<N>: SupportedLaneCount,
129        {
130        }
131
132        impl<const N: usize> SimdUint for Simd<$ty, N>
133        where
134            LaneCount<N>: SupportedLaneCount,
135        {
136            type Scalar = $ty;
137            type Cast<T: SimdElement> = Simd<T, N>;
138
139            #[inline]
140            fn cast<T: SimdCast>(self) -> Self::Cast<T> {
141                // Safety: supported types are guaranteed by SimdCast
142                unsafe { core::intrinsics::simd::simd_as(self) }
143            }
144
145            #[inline]
146            fn wrapping_neg(self) -> Self {
147                use crate::simd::num::SimdInt;
148                (-self.cast::<$signed>()).cast()
149            }
150
151            #[inline]
152            fn saturating_add(self, second: Self) -> Self {
153                // Safety: `self` is a vector
154                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
155            }
156
157            #[inline]
158            fn saturating_sub(self, second: Self) -> Self {
159                // Safety: `self` is a vector
160                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
161            }
162
163            #[inline]
164            fn abs_diff(self, second: Self) -> Self {
165                let max = self.simd_max(second);
166                let min = self.simd_min(second);
167                max - min
168            }
169
170            #[inline]
171            fn reduce_sum(self) -> Self::Scalar {
172                // Safety: `self` is an integer vector
173                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
174            }
175
176            #[inline]
177            fn reduce_product(self) -> Self::Scalar {
178                // Safety: `self` is an integer vector
179                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
180            }
181
182            #[inline]
183            fn reduce_max(self) -> Self::Scalar {
184                // Safety: `self` is an integer vector
185                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
186            }
187
188            #[inline]
189            fn reduce_min(self) -> Self::Scalar {
190                // Safety: `self` is an integer vector
191                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
192            }
193
194            #[inline]
195            fn reduce_and(self) -> Self::Scalar {
196                // Safety: `self` is an integer vector
197                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
198            }
199
200            #[inline]
201            fn reduce_or(self) -> Self::Scalar {
202                // Safety: `self` is an integer vector
203                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
204            }
205
206            #[inline]
207            fn reduce_xor(self) -> Self::Scalar {
208                // Safety: `self` is an integer vector
209                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
210            }
211
212            #[inline]
213            fn swap_bytes(self) -> Self {
214                // Safety: `self` is an integer vector
215                unsafe { core::intrinsics::simd::simd_bswap(self) }
216            }
217
218            #[inline]
219            fn reverse_bits(self) -> Self {
220                // Safety: `self` is an integer vector
221                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
222            }
223
224            #[inline]
225            fn count_ones(self) -> Self {
226                // Safety: `self` is an integer vector
227                unsafe { core::intrinsics::simd::simd_ctpop(self) }
228            }
229
230            #[inline]
231            fn count_zeros(self) -> Self {
232                (!self).count_ones()
233            }
234
235            #[inline]
236            fn leading_zeros(self) -> Self {
237                // Safety: `self` is an integer vector
238                unsafe { core::intrinsics::simd::simd_ctlz(self) }
239            }
240
241            #[inline]
242            fn trailing_zeros(self) -> Self {
243                // Safety: `self` is an integer vector
244                unsafe { core::intrinsics::simd::simd_cttz(self) }
245            }
246
247            #[inline]
248            fn leading_ones(self) -> Self {
249                (!self).leading_zeros()
250            }
251
252            #[inline]
253            fn trailing_ones(self) -> Self {
254                (!self).trailing_zeros()
255            }
256        }
257        )*
258    }
259}
260
261impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) }