int.rs - source
Description: Source of the Rust file `library/core/src/../../portable-simd/crates/core_simd/src/simd/num/int.rs`.

#
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) }