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

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