| use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub}; |
| use crate::simd::{LaneCount, Simd, SupportedLaneCount}; |
| |
| macro_rules! impl_uint_arith { |
| ($($ty:ty),+) => { |
| $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount { |
| |
| /// Lanewise saturating add. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] |
| /// let x = Simd::from_array([2, 1, 0, MAX]); |
| /// let max = Simd::splat(MAX); |
| /// let unsat = x + max; |
| /// let sat = x.saturating_add(max); |
| /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1])); |
| /// assert_eq!(sat, max); |
| /// ``` |
| #[inline] |
| pub fn saturating_add(self, second: Self) -> Self { |
| // Safety: `self` is a vector |
| unsafe { simd_saturating_add(self, second) } |
| } |
| |
| /// Lanewise saturating subtract. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::MAX;")] |
| /// let x = Simd::from_array([2, 1, 0, MAX]); |
| /// let max = Simd::splat(MAX); |
| /// let unsat = x - max; |
| /// let sat = x.saturating_sub(max); |
| /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0])); |
| /// assert_eq!(sat, Simd::splat(0)); |
| #[inline] |
| pub fn saturating_sub(self, second: Self) -> Self { |
| // Safety: `self` is a vector |
| unsafe { simd_saturating_sub(self, second) } |
| } |
| })+ |
| } |
| } |
| |
| macro_rules! impl_int_arith { |
| ($($ty:ty),+) => { |
| $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount { |
| |
| /// Lanewise saturating add. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] |
| /// let x = Simd::from_array([MIN, 0, 1, MAX]); |
| /// let max = Simd::splat(MAX); |
| /// let unsat = x + max; |
| /// let sat = x.saturating_add(max); |
| /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2])); |
| /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX])); |
| /// ``` |
| #[inline] |
| pub fn saturating_add(self, second: Self) -> Self { |
| // Safety: `self` is a vector |
| unsafe { simd_saturating_add(self, second) } |
| } |
| |
| /// Lanewise saturating subtract. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] |
| /// let x = Simd::from_array([MIN, -2, -1, MAX]); |
| /// let max = Simd::splat(MAX); |
| /// let unsat = x - max; |
| /// let sat = x.saturating_sub(max); |
| /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0])); |
| /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0])); |
| #[inline] |
| pub fn saturating_sub(self, second: Self) -> Self { |
| // Safety: `self` is a vector |
| unsafe { simd_saturating_sub(self, second) } |
| } |
| |
| /// Lanewise absolute value, implemented in Rust. |
| /// Every lane becomes its absolute value. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] |
| /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]); |
| /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0])); |
| /// ``` |
| #[inline] |
| pub fn abs(self) -> Self { |
| const SHR: $ty = <$ty>::BITS as $ty - 1; |
| let m = self >> Simd::splat(SHR); |
| (self^m) - m |
| } |
| |
| /// Lanewise saturating absolute value, implemented in Rust. |
| /// As abs(), except the MIN value becomes MAX instead of itself. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] |
| /// let xs = Simd::from_array([MIN, -2, 0, 3]); |
| /// let unsat = xs.abs(); |
| /// let sat = xs.saturating_abs(); |
| /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3])); |
| /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3])); |
| /// ``` |
| #[inline] |
| pub fn saturating_abs(self) -> Self { |
| // arith shift for -1 or 0 mask based on sign bit, giving 2s complement |
| const SHR: $ty = <$ty>::BITS as $ty - 1; |
| let m = self >> Simd::splat(SHR); |
| (self^m).saturating_sub(m) |
| } |
| |
| /// Lanewise saturating negation, implemented in Rust. |
| /// As neg(), except the MIN value becomes MAX instead of itself. |
| /// |
| /// # Examples |
| /// ``` |
| /// # #![feature(portable_simd)] |
| /// # use core::simd::Simd; |
| #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")] |
| /// let x = Simd::from_array([MIN, -2, 3, MAX]); |
| /// let unsat = -x; |
| /// let sat = x.saturating_neg(); |
| /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1])); |
| /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1])); |
| /// ``` |
| #[inline] |
| pub fn saturating_neg(self) -> Self { |
| Self::splat(0).saturating_sub(self) |
| } |
| })+ |
| } |
| } |
| |
| impl_uint_arith! { u8, u16, u32, u64, usize } |
| impl_int_arith! { i8, i16, i32, i64, isize } |