Skip to main content

core_simd/simd/num/
int.rs

1use crate::simd::{
2    Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint,
3};
4
5/// Operations on SIMD vectors of signed integers.
6pub impl(self) trait SimdInt: Copy {
7    /// Mask type used for manipulating this SIMD vector type.
8    type Mask;
9
10    /// Scalar type contained by this SIMD vector type.
11    type Scalar;
12
13    /// A SIMD vector of unsigned integers with the same element size.
14    type Unsigned;
15
16    /// A SIMD vector with a different element type.
17    type Cast<T: SimdElement>;
18
19    /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
20    ///
21    /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
22    /// other integer types, and saturating to float types).
23    #[must_use]
24    fn cast<T: SimdCast>(self) -> Self::Cast<T>;
25
26    /// Lanewise saturating add.
27    ///
28    /// # Examples
29    /// ```
30    /// # #![feature(portable_simd)]
31    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
32    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
33    /// # use simd::prelude::*;
34    /// use core::i32::{MIN, MAX};
35    /// let x = Simd::from_array([MIN, 0, 1, MAX]);
36    /// let max = Simd::splat(MAX);
37    /// let unsat = x + max;
38    /// let sat = x.saturating_add(max);
39    /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
40    /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
41    /// ```
42    fn saturating_add(self, second: Self) -> Self;
43
44    /// Lanewise saturating subtract.
45    ///
46    /// # Examples
47    /// ```
48    /// # #![feature(portable_simd)]
49    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
50    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
51    /// # use simd::prelude::*;
52    /// use core::i32::{MIN, MAX};
53    /// let x = Simd::from_array([MIN, -2, -1, MAX]);
54    /// let max = Simd::splat(MAX);
55    /// let unsat = x - max;
56    /// let sat = x.saturating_sub(max);
57    /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
58    /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
59    /// ```
60    fn saturating_sub(self, second: Self) -> Self;
61
62    /// Lanewise absolute value, implemented in Rust.
63    /// Every element becomes its absolute value.
64    ///
65    /// # Examples
66    /// ```
67    /// # #![feature(portable_simd)]
68    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
69    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
70    /// # use simd::prelude::*;
71    /// use core::i32::{MIN, MAX};
72    /// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]);
73    /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
74    /// ```
75    fn abs(self) -> Self;
76
77    /// Lanewise absolute difference.
78    /// Every element becomes the absolute difference of `self` and `second`.
79    ///
80    /// # Examples
81    /// ```
82    /// # #![feature(portable_simd)]
83    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
84    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
85    /// # use simd::prelude::*;
86    /// use core::i32::{MIN, MAX};
87    /// let a = Simd::from_array([MIN, MAX, 100, -100]);
88    /// let b = Simd::from_array([MAX, MIN, -80, -120]);
89    /// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20]));
90    /// ```
91    fn abs_diff(self, second: Self) -> Self::Unsigned;
92
93    /// Lanewise saturating absolute value, implemented in Rust.
94    /// As abs(), except the MIN value becomes MAX instead of itself.
95    ///
96    /// # Examples
97    /// ```
98    /// # #![feature(portable_simd)]
99    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
100    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
101    /// # use simd::prelude::*;
102    /// use core::i32::{MIN, MAX};
103    /// let xs = Simd::from_array([MIN, -2, 0, 3]);
104    /// let unsat = xs.abs();
105    /// let sat = xs.saturating_abs();
106    /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
107    /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
108    /// ```
109    fn saturating_abs(self) -> Self;
110
111    /// Lanewise saturating negation, implemented in Rust.
112    /// As neg(), except the MIN value becomes MAX instead of itself.
113    ///
114    /// # Examples
115    /// ```
116    /// # #![feature(portable_simd)]
117    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
118    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
119    /// # use simd::prelude::*;
120    /// use core::i32::{MIN, MAX};
121    /// let x = Simd::from_array([MIN, -2, 3, MAX]);
122    /// let unsat = -x;
123    /// let sat = x.saturating_neg();
124    /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
125    /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
126    /// ```
127    fn saturating_neg(self) -> Self;
128
129    /// Returns true for each positive element and false if it is zero or negative.
130    fn is_positive(self) -> Self::Mask;
131
132    /// Returns true for each negative element and false if it is zero or positive.
133    fn is_negative(self) -> Self::Mask;
134
135    /// Returns numbers representing the sign of each element.
136    /// * `0` if the number is zero
137    /// * `1` if the number is positive
138    /// * `-1` if the number is negative
139    fn signum(self) -> Self;
140
141    /// Returns the sum of the elements of the vector, with wrapping addition.
142    ///
143    /// # Examples
144    ///
145    /// ```
146    /// # #![feature(portable_simd)]
147    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
148    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
149    /// # use simd::prelude::*;
150    /// let v = i32x4::from_array([1, 2, 3, 4]);
151    /// assert_eq!(v.reduce_sum(), 10);
152    ///
153    /// // SIMD integer addition is always wrapping
154    /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]);
155    /// assert_eq!(v.reduce_sum(), i32::MIN);
156    /// ```
157    fn reduce_sum(self) -> Self::Scalar;
158
159    /// Returns the product of the elements of the vector, with wrapping multiplication.
160    ///
161    /// # Examples
162    ///
163    /// ```
164    /// # #![feature(portable_simd)]
165    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
166    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
167    /// # use simd::prelude::*;
168    /// let v = i32x4::from_array([1, 2, 3, 4]);
169    /// assert_eq!(v.reduce_product(), 24);
170    ///
171    /// // SIMD integer multiplication is always wrapping
172    /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]);
173    /// assert!(v.reduce_product() < i32::MAX);
174    /// ```
175    fn reduce_product(self) -> Self::Scalar;
176
177    /// Returns the maximum element in the vector.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// # #![feature(portable_simd)]
183    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
184    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
185    /// # use simd::prelude::*;
186    /// let v = i32x4::from_array([1, 2, 3, 4]);
187    /// assert_eq!(v.reduce_max(), 4);
188    /// ```
189    fn reduce_max(self) -> Self::Scalar;
190
191    /// Returns the minimum element in the vector.
192    ///
193    /// # Examples
194    ///
195    /// ```
196    /// # #![feature(portable_simd)]
197    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
198    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
199    /// # use simd::prelude::*;
200    /// let v = i32x4::from_array([1, 2, 3, 4]);
201    /// assert_eq!(v.reduce_min(), 1);
202    /// ```
203    fn reduce_min(self) -> Self::Scalar;
204
205    /// Returns the cumulative bitwise "and" across the elements of the vector.
206    fn reduce_and(self) -> Self::Scalar;
207
208    /// Returns the cumulative bitwise "or" across the elements of the vector.
209    fn reduce_or(self) -> Self::Scalar;
210
211    /// Returns the cumulative bitwise "xor" across the elements of the vector.
212    fn reduce_xor(self) -> Self::Scalar;
213
214    /// Reverses the byte order of each element.
215    fn swap_bytes(self) -> Self;
216
217    /// Reverses the order of bits in each elemnent.
218    /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
219    fn reverse_bits(self) -> Self;
220
221    /// Returns the number of ones in the binary representation of each element.
222    fn count_ones(self) -> Self::Unsigned;
223
224    /// Returns the number of zeros in the binary representation of each element.
225    fn count_zeros(self) -> Self::Unsigned;
226
227    /// Returns the number of leading zeros in the binary representation of each element.
228    fn leading_zeros(self) -> Self::Unsigned;
229
230    /// Returns the number of trailing zeros in the binary representation of each element.
231    fn trailing_zeros(self) -> Self::Unsigned;
232
233    /// Returns the number of leading ones in the binary representation of each element.
234    fn leading_ones(self) -> Self::Unsigned;
235
236    /// Returns the number of trailing ones in the binary representation of each element.
237    fn trailing_ones(self) -> Self::Unsigned;
238}
239
240macro_rules! impl_trait {
241    { $($ty:ident ($unsigned:ident)),* } => {
242        $(
243        impl<const N: usize> SimdInt for Simd<$ty, N> {
244            type Mask = Mask<<$ty as SimdElement>::Mask, N>;
245            type Scalar = $ty;
246            type Unsigned = Simd<$unsigned, N>;
247            type Cast<T: SimdElement> = Simd<T, N>;
248
249            #[inline]
250            fn cast<T: SimdCast>(self) -> Self::Cast<T> {
251                // Safety: supported types are guaranteed by SimdCast
252                unsafe { core::intrinsics::simd::simd_as(self) }
253            }
254
255            #[inline]
256            fn saturating_add(self, second: Self) -> Self {
257                // Safety: `self` is a vector
258                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
259            }
260
261            #[inline]
262            fn saturating_sub(self, second: Self) -> Self {
263                // Safety: `self` is a vector
264                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
265            }
266
267            #[inline]
268            fn abs(self) -> Self {
269                const SHR: $ty = <$ty>::BITS as $ty - 1;
270                let m = self >> Simd::splat(SHR);
271                (self^m) - m
272            }
273
274            #[inline]
275            fn abs_diff(self, second: Self) -> Self::Unsigned {
276                let max = self.simd_max(second);
277                let min = self.simd_min(second);
278                (max - min).cast()
279            }
280
281            #[inline]
282            fn saturating_abs(self) -> Self {
283                // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
284                const SHR: $ty = <$ty>::BITS as $ty - 1;
285                let m = self >> Simd::splat(SHR);
286                (self^m).saturating_sub(m)
287            }
288
289            #[inline]
290            fn saturating_neg(self) -> Self {
291                Self::splat(0).saturating_sub(self)
292            }
293
294            #[inline]
295            fn is_positive(self) -> Self::Mask {
296                self.simd_gt(Self::splat(0))
297            }
298
299            #[inline]
300            fn is_negative(self) -> Self::Mask {
301                self.simd_lt(Self::splat(0))
302            }
303
304            #[inline]
305            fn signum(self) -> Self {
306                self.is_positive().select(
307                    Self::splat(1),
308                    self.is_negative().select(Self::splat(-1), Self::splat(0))
309                )
310            }
311
312            #[inline]
313            fn reduce_sum(self) -> Self::Scalar {
314                // Safety: `self` is an integer vector
315                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
316            }
317
318            #[inline]
319            fn reduce_product(self) -> Self::Scalar {
320                // Safety: `self` is an integer vector
321                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
322            }
323
324            #[inline]
325            fn reduce_max(self) -> Self::Scalar {
326                // Safety: `self` is an integer vector
327                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
328            }
329
330            #[inline]
331            fn reduce_min(self) -> Self::Scalar {
332                // Safety: `self` is an integer vector
333                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
334            }
335
336            #[inline]
337            fn reduce_and(self) -> Self::Scalar {
338                // Safety: `self` is an integer vector
339                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
340            }
341
342            #[inline]
343            fn reduce_or(self) -> Self::Scalar {
344                // Safety: `self` is an integer vector
345                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
346            }
347
348            #[inline]
349            fn reduce_xor(self) -> Self::Scalar {
350                // Safety: `self` is an integer vector
351                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
352            }
353
354            #[inline]
355            fn swap_bytes(self) -> Self {
356                // Safety: `self` is an integer vector
357                unsafe { core::intrinsics::simd::simd_bswap(self) }
358            }
359
360            #[inline]
361            fn reverse_bits(self) -> Self {
362                // Safety: `self` is an integer vector
363                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
364            }
365
366            #[inline]
367            fn count_ones(self) -> Self::Unsigned {
368                self.cast::<$unsigned>().count_ones()
369            }
370
371            #[inline]
372            fn count_zeros(self) -> Self::Unsigned {
373                self.cast::<$unsigned>().count_zeros()
374            }
375
376            #[inline]
377            fn leading_zeros(self) -> Self::Unsigned {
378                self.cast::<$unsigned>().leading_zeros()
379            }
380
381            #[inline]
382            fn trailing_zeros(self) -> Self::Unsigned {
383                self.cast::<$unsigned>().trailing_zeros()
384            }
385
386            #[inline]
387            fn leading_ones(self) -> Self::Unsigned {
388                self.cast::<$unsigned>().leading_ones()
389            }
390
391            #[inline]
392            fn trailing_ones(self) -> Self::Unsigned {
393                self.cast::<$unsigned>().trailing_ones()
394            }
395        }
396        )*
397    }
398}
399
400impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) }