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