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

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