core_simd/simd/num/
int.rs

1use super::sealed::Sealed;
2use crate::simd::{
3    Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint,
4};
5
6/// Operations on SIMD vectors of signed integers.
7pub trait SimdInt: Copy + Sealed {
8    /// Mask type used for manipulating this SIMD vector type.
9    type Mask;
10
11    /// Scalar type contained by this SIMD vector type.
12    type Scalar;
13
14    /// A SIMD vector of unsigned integers with the same element size.
15    type Unsigned;
16
17    /// A SIMD vector with a different element type.
18    type Cast<T: SimdElement>;
19
20    /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
21    ///
22    /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
23    /// other integer types, and saturating to float types).
24    #[must_use]
25    fn cast<T: SimdCast>(self) -> Self::Cast<T>;
26
27    /// Lanewise saturating add.
28    ///
29    /// # Examples
30    /// ```
31    /// # #![feature(portable_simd)]
32    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
33    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
34    /// # use simd::prelude::*;
35    /// use core::i32::{MIN, MAX};
36    /// let x = Simd::from_array([MIN, 0, 1, MAX]);
37    /// let max = Simd::splat(MAX);
38    /// let unsat = x + max;
39    /// let sat = x.saturating_add(max);
40    /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
41    /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
42    /// ```
43    fn saturating_add(self, second: Self) -> Self;
44
45    /// Lanewise saturating subtract.
46    ///
47    /// # Examples
48    /// ```
49    /// # #![feature(portable_simd)]
50    /// # #[cfg(feature = "as_crate")] use core_simd::simd;
51    /// # #[cfg(not(feature = "as_crate"))] use core::simd;
52    /// # use simd::prelude::*;
53    /// use core::i32::{MIN, MAX};
54    /// let x = Simd::from_array([MIN, -2, -1, MAX]);
55    /// let max = Simd::splat(MAX);
56    /// let unsat = x - max;
57    /// let sat = x.saturating_sub(max);
58    /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
59    /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
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> Sealed for Simd<$ty, N> {}
244
245        impl<const N: usize> SimdInt for Simd<$ty, N> {
246            type Mask = Mask<<$ty as SimdElement>::Mask, N>;
247            type Scalar = $ty;
248            type Unsigned = Simd<$unsigned, N>;
249            type Cast<T: SimdElement> = Simd<T, N>;
250
251            #[inline]
252            fn cast<T: SimdCast>(self) -> Self::Cast<T> {
253                // Safety: supported types are guaranteed by SimdCast
254                unsafe { core::intrinsics::simd::simd_as(self) }
255            }
256
257            #[inline]
258            fn saturating_add(self, second: Self) -> Self {
259                // Safety: `self` is a vector
260                unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
261            }
262
263            #[inline]
264            fn saturating_sub(self, second: Self) -> Self {
265                // Safety: `self` is a vector
266                unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
267            }
268
269            #[inline]
270            fn abs(self) -> Self {
271                const SHR: $ty = <$ty>::BITS as $ty - 1;
272                let m = self >> Simd::splat(SHR);
273                (self^m) - m
274            }
275
276            #[inline]
277            fn abs_diff(self, second: Self) -> Self::Unsigned {
278                let max = self.simd_max(second);
279                let min = self.simd_min(second);
280                (max - min).cast()
281            }
282
283            #[inline]
284            fn saturating_abs(self) -> Self {
285                // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
286                const SHR: $ty = <$ty>::BITS as $ty - 1;
287                let m = self >> Simd::splat(SHR);
288                (self^m).saturating_sub(m)
289            }
290
291            #[inline]
292            fn saturating_neg(self) -> Self {
293                Self::splat(0).saturating_sub(self)
294            }
295
296            #[inline]
297            fn is_positive(self) -> Self::Mask {
298                self.simd_gt(Self::splat(0))
299            }
300
301            #[inline]
302            fn is_negative(self) -> Self::Mask {
303                self.simd_lt(Self::splat(0))
304            }
305
306            #[inline]
307            fn signum(self) -> Self {
308                self.is_positive().select(
309                    Self::splat(1),
310                    self.is_negative().select(Self::splat(-1), Self::splat(0))
311                )
312            }
313
314            #[inline]
315            fn reduce_sum(self) -> Self::Scalar {
316                // Safety: `self` is an integer vector
317                unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
318            }
319
320            #[inline]
321            fn reduce_product(self) -> Self::Scalar {
322                // Safety: `self` is an integer vector
323                unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
324            }
325
326            #[inline]
327            fn reduce_max(self) -> Self::Scalar {
328                // Safety: `self` is an integer vector
329                unsafe { core::intrinsics::simd::simd_reduce_max(self) }
330            }
331
332            #[inline]
333            fn reduce_min(self) -> Self::Scalar {
334                // Safety: `self` is an integer vector
335                unsafe { core::intrinsics::simd::simd_reduce_min(self) }
336            }
337
338            #[inline]
339            fn reduce_and(self) -> Self::Scalar {
340                // Safety: `self` is an integer vector
341                unsafe { core::intrinsics::simd::simd_reduce_and(self) }
342            }
343
344            #[inline]
345            fn reduce_or(self) -> Self::Scalar {
346                // Safety: `self` is an integer vector
347                unsafe { core::intrinsics::simd::simd_reduce_or(self) }
348            }
349
350            #[inline]
351            fn reduce_xor(self) -> Self::Scalar {
352                // Safety: `self` is an integer vector
353                unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
354            }
355
356            #[inline]
357            fn swap_bytes(self) -> Self {
358                // Safety: `self` is an integer vector
359                unsafe { core::intrinsics::simd::simd_bswap(self) }
360            }
361
362            #[inline]
363            fn reverse_bits(self) -> Self {
364                // Safety: `self` is an integer vector
365                unsafe { core::intrinsics::simd::simd_bitreverse(self) }
366            }
367
368            #[inline]
369            fn count_ones(self) -> Self::Unsigned {
370                self.cast::<$unsigned>().count_ones()
371            }
372
373            #[inline]
374            fn count_zeros(self) -> Self::Unsigned {
375                self.cast::<$unsigned>().count_zeros()
376            }
377
378            #[inline]
379            fn leading_zeros(self) -> Self::Unsigned {
380                self.cast::<$unsigned>().leading_zeros()
381            }
382
383            #[inline]
384            fn trailing_zeros(self) -> Self::Unsigned {
385                self.cast::<$unsigned>().trailing_zeros()
386            }
387
388            #[inline]
389            fn leading_ones(self) -> Self::Unsigned {
390                self.cast::<$unsigned>().leading_ones()
391            }
392
393            #[inline]
394            fn trailing_ones(self) -> Self::Unsigned {
395                self.cast::<$unsigned>().trailing_ones()
396            }
397        }
398        )*
399    }
400}
401
402impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) }