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