]> git.lizzy.rs Git - rust.git/blob - library/portable-simd/crates/core_simd/src/math.rs
Auto merge of #90423 - Aaron1011:deduplicate-projection, r=jackh726
[rust.git] / library / portable-simd / crates / core_simd / src / math.rs
1 use crate::simd::intrinsics::{simd_saturating_add, simd_saturating_sub};
2 use crate::simd::{LaneCount, Simd, SupportedLaneCount};
3
4 macro_rules! impl_uint_arith {
5     ($($ty:ty),+) => {
6         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
7
8             /// Lanewise saturating add.
9             ///
10             /// # Examples
11             /// ```
12             /// # #![feature(portable_simd)]
13             /// # #[cfg(feature = "std")] use core_simd::Simd;
14             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
15             #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
16             /// let x = Simd::from_array([2, 1, 0, MAX]);
17             /// let max = Simd::splat(MAX);
18             /// let unsat = x + max;
19             /// let sat = x.saturating_add(max);
20             /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
21             /// assert_eq!(sat, max);
22             /// ```
23             #[inline]
24             pub fn saturating_add(self, second: Self) -> Self {
25                 unsafe { simd_saturating_add(self, second) }
26             }
27
28             /// Lanewise saturating subtract.
29             ///
30             /// # Examples
31             /// ```
32             /// # #![feature(portable_simd)]
33             /// # #[cfg(feature = "std")] use core_simd::Simd;
34             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
35             #[doc = concat!("# use core::", stringify!($ty), "::MAX;")]
36             /// let x = Simd::from_array([2, 1, 0, MAX]);
37             /// let max = Simd::splat(MAX);
38             /// let unsat = x - max;
39             /// let sat = x.saturating_sub(max);
40             /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
41             /// assert_eq!(sat, Simd::splat(0));
42             #[inline]
43             pub fn saturating_sub(self, second: Self) -> Self {
44                 unsafe { simd_saturating_sub(self, second) }
45             }
46         })+
47     }
48 }
49
50 macro_rules! impl_int_arith {
51     ($($ty:ty),+) => {
52         $( impl<const LANES: usize> Simd<$ty, LANES> where LaneCount<LANES>: SupportedLaneCount {
53
54             /// Lanewise saturating add.
55             ///
56             /// # Examples
57             /// ```
58             /// # #![feature(portable_simd)]
59             /// # #[cfg(feature = "std")] use core_simd::Simd;
60             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
61             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
62             /// let x = Simd::from_array([MIN, 0, 1, MAX]);
63             /// let max = Simd::splat(MAX);
64             /// let unsat = x + max;
65             /// let sat = x.saturating_add(max);
66             /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
67             /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
68             /// ```
69             #[inline]
70             pub fn saturating_add(self, second: Self) -> Self {
71                 unsafe { simd_saturating_add(self, second) }
72             }
73
74             /// Lanewise saturating subtract.
75             ///
76             /// # Examples
77             /// ```
78             /// # #![feature(portable_simd)]
79             /// # #[cfg(feature = "std")] use core_simd::Simd;
80             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
81             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
82             /// let x = Simd::from_array([MIN, -2, -1, MAX]);
83             /// let max = Simd::splat(MAX);
84             /// let unsat = x - max;
85             /// let sat = x.saturating_sub(max);
86             /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
87             /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
88             #[inline]
89             pub fn saturating_sub(self, second: Self) -> Self {
90                 unsafe { simd_saturating_sub(self, second) }
91             }
92
93             /// Lanewise absolute value, implemented in Rust.
94             /// Every lane becomes its absolute value.
95             ///
96             /// # Examples
97             /// ```
98             /// # #![feature(portable_simd)]
99             /// # #[cfg(feature = "std")] use core_simd::Simd;
100             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
101             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
102             /// let xs = Simd::from_array([MIN, MIN +1, -5, 0]);
103             /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
104             /// ```
105             #[inline]
106             pub fn abs(self) -> Self {
107                 const SHR: $ty = <$ty>::BITS as $ty - 1;
108                 let m = self >> Simd::splat(SHR);
109                 (self^m) - m
110             }
111
112             /// Lanewise saturating absolute value, implemented in Rust.
113             /// As abs(), except the MIN value becomes MAX instead of itself.
114             ///
115             /// # Examples
116             /// ```
117             /// # #![feature(portable_simd)]
118             /// # #[cfg(feature = "std")] use core_simd::Simd;
119             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
120             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
121             /// let xs = Simd::from_array([MIN, -2, 0, 3]);
122             /// let unsat = xs.abs();
123             /// let sat = xs.saturating_abs();
124             /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
125             /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
126             /// ```
127             #[inline]
128             pub fn saturating_abs(self) -> Self {
129                 // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
130                 const SHR: $ty = <$ty>::BITS as $ty - 1;
131                 let m = self >> Simd::splat(SHR);
132                 (self^m).saturating_sub(m)
133             }
134
135             /// Lanewise saturating negation, implemented in Rust.
136             /// As neg(), except the MIN value becomes MAX instead of itself.
137             ///
138             /// # Examples
139             /// ```
140             /// # #![feature(portable_simd)]
141             /// # #[cfg(feature = "std")] use core_simd::Simd;
142             /// # #[cfg(not(feature = "std"))] use core::simd::Simd;
143             #[doc = concat!("# use core::", stringify!($ty), "::{MIN, MAX};")]
144             /// let x = Simd::from_array([MIN, -2, 3, MAX]);
145             /// let unsat = -x;
146             /// let sat = x.saturating_neg();
147             /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
148             /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
149             /// ```
150             #[inline]
151             pub fn saturating_neg(self) -> Self {
152                 Self::splat(0).saturating_sub(self)
153             }
154         })+
155     }
156 }
157
158 impl_uint_arith! { u8, u16, u32, u64, usize }
159 impl_int_arith! { i8, i16, i32, i64, isize }