core_simd/simd/num/int.rs
1use crate::simd::{
2 Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint,
3};
4
5/// Operations on SIMD vectors of signed integers.
6pub impl(self) trait SimdInt: Copy {
7 /// Mask type used for manipulating this SIMD vector type.
8 type Mask;
9
10 /// Scalar type contained by this SIMD vector type.
11 type Scalar;
12
13 /// A SIMD vector of unsigned integers with the same element size.
14 type Unsigned;
15
16 /// A SIMD vector with a different element type.
17 type Cast<T: SimdElement>;
18
19 /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
20 ///
21 /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
22 /// other integer types, and saturating to float types).
23 #[must_use]
24 fn cast<T: SimdCast>(self) -> Self::Cast<T>;
25
26 /// Lanewise saturating add.
27 ///
28 /// # Examples
29 /// ```
30 /// # #![feature(portable_simd)]
31 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
32 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
33 /// # use simd::prelude::*;
34 /// use core::i32::{MIN, MAX};
35 /// let x = Simd::from_array([MIN, 0, 1, MAX]);
36 /// let max = Simd::splat(MAX);
37 /// let unsat = x + max;
38 /// let sat = x.saturating_add(max);
39 /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
40 /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
41 /// ```
42 fn saturating_add(self, second: Self) -> Self;
43
44 /// Lanewise saturating subtract.
45 ///
46 /// # Examples
47 /// ```
48 /// # #![feature(portable_simd)]
49 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
50 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
51 /// # use simd::prelude::*;
52 /// use core::i32::{MIN, MAX};
53 /// let x = Simd::from_array([MIN, -2, -1, MAX]);
54 /// let max = Simd::splat(MAX);
55 /// let unsat = x - max;
56 /// let sat = x.saturating_sub(max);
57 /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
58 /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
59 /// ```
60 fn saturating_sub(self, second: Self) -> Self;
61
62 /// Lanewise absolute value, implemented in Rust.
63 /// Every element becomes its absolute value.
64 ///
65 /// # Examples
66 /// ```
67 /// # #![feature(portable_simd)]
68 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
69 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
70 /// # use simd::prelude::*;
71 /// use core::i32::{MIN, MAX};
72 /// let xs = Simd::from_array([MIN, MIN + 1, -5, 0]);
73 /// assert_eq!(xs.abs(), Simd::from_array([MIN, MAX, 5, 0]));
74 /// ```
75 fn abs(self) -> Self;
76
77 /// Lanewise absolute difference.
78 /// Every element becomes the absolute difference of `self` and `second`.
79 ///
80 /// # Examples
81 /// ```
82 /// # #![feature(portable_simd)]
83 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
84 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
85 /// # use simd::prelude::*;
86 /// use core::i32::{MIN, MAX};
87 /// let a = Simd::from_array([MIN, MAX, 100, -100]);
88 /// let b = Simd::from_array([MAX, MIN, -80, -120]);
89 /// assert_eq!(a.abs_diff(b), Simd::from_array([u32::MAX, u32::MAX, 180, 20]));
90 /// ```
91 fn abs_diff(self, second: Self) -> Self::Unsigned;
92
93 /// Lanewise saturating absolute value, implemented in Rust.
94 /// As abs(), except the MIN value becomes MAX instead of itself.
95 ///
96 /// # Examples
97 /// ```
98 /// # #![feature(portable_simd)]
99 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
100 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
101 /// # use simd::prelude::*;
102 /// use core::i32::{MIN, MAX};
103 /// let xs = Simd::from_array([MIN, -2, 0, 3]);
104 /// let unsat = xs.abs();
105 /// let sat = xs.saturating_abs();
106 /// assert_eq!(unsat, Simd::from_array([MIN, 2, 0, 3]));
107 /// assert_eq!(sat, Simd::from_array([MAX, 2, 0, 3]));
108 /// ```
109 fn saturating_abs(self) -> Self;
110
111 /// Lanewise saturating negation, implemented in Rust.
112 /// As neg(), except the MIN value becomes MAX instead of itself.
113 ///
114 /// # Examples
115 /// ```
116 /// # #![feature(portable_simd)]
117 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
118 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
119 /// # use simd::prelude::*;
120 /// use core::i32::{MIN, MAX};
121 /// let x = Simd::from_array([MIN, -2, 3, MAX]);
122 /// let unsat = -x;
123 /// let sat = x.saturating_neg();
124 /// assert_eq!(unsat, Simd::from_array([MIN, 2, -3, MIN + 1]));
125 /// assert_eq!(sat, Simd::from_array([MAX, 2, -3, MIN + 1]));
126 /// ```
127 fn saturating_neg(self) -> Self;
128
129 /// Returns true for each positive element and false if it is zero or negative.
130 fn is_positive(self) -> Self::Mask;
131
132 /// Returns true for each negative element and false if it is zero or positive.
133 fn is_negative(self) -> Self::Mask;
134
135 /// Returns numbers representing the sign of each element.
136 /// * `0` if the number is zero
137 /// * `1` if the number is positive
138 /// * `-1` if the number is negative
139 fn signum(self) -> Self;
140
141 /// Returns the sum of the elements of the vector, with wrapping addition.
142 ///
143 /// # Examples
144 ///
145 /// ```
146 /// # #![feature(portable_simd)]
147 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
148 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
149 /// # use simd::prelude::*;
150 /// let v = i32x4::from_array([1, 2, 3, 4]);
151 /// assert_eq!(v.reduce_sum(), 10);
152 ///
153 /// // SIMD integer addition is always wrapping
154 /// let v = i32x4::from_array([i32::MAX, 1, 0, 0]);
155 /// assert_eq!(v.reduce_sum(), i32::MIN);
156 /// ```
157 fn reduce_sum(self) -> Self::Scalar;
158
159 /// Returns the product of the elements of the vector, with wrapping multiplication.
160 ///
161 /// # Examples
162 ///
163 /// ```
164 /// # #![feature(portable_simd)]
165 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
166 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
167 /// # use simd::prelude::*;
168 /// let v = i32x4::from_array([1, 2, 3, 4]);
169 /// assert_eq!(v.reduce_product(), 24);
170 ///
171 /// // SIMD integer multiplication is always wrapping
172 /// let v = i32x4::from_array([i32::MAX, 2, 1, 1]);
173 /// assert!(v.reduce_product() < i32::MAX);
174 /// ```
175 fn reduce_product(self) -> Self::Scalar;
176
177 /// Returns the maximum element in the vector.
178 ///
179 /// # Examples
180 ///
181 /// ```
182 /// # #![feature(portable_simd)]
183 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
184 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
185 /// # use simd::prelude::*;
186 /// let v = i32x4::from_array([1, 2, 3, 4]);
187 /// assert_eq!(v.reduce_max(), 4);
188 /// ```
189 fn reduce_max(self) -> Self::Scalar;
190
191 /// Returns the minimum element in the vector.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// # #![feature(portable_simd)]
197 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
198 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
199 /// # use simd::prelude::*;
200 /// let v = i32x4::from_array([1, 2, 3, 4]);
201 /// assert_eq!(v.reduce_min(), 1);
202 /// ```
203 fn reduce_min(self) -> Self::Scalar;
204
205 /// Returns the cumulative bitwise "and" across the elements of the vector.
206 fn reduce_and(self) -> Self::Scalar;
207
208 /// Returns the cumulative bitwise "or" across the elements of the vector.
209 fn reduce_or(self) -> Self::Scalar;
210
211 /// Returns the cumulative bitwise "xor" across the elements of the vector.
212 fn reduce_xor(self) -> Self::Scalar;
213
214 /// Reverses the byte order of each element.
215 fn swap_bytes(self) -> Self;
216
217 /// Reverses the order of bits in each elemnent.
218 /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
219 fn reverse_bits(self) -> Self;
220
221 /// Returns the number of ones in the binary representation of each element.
222 fn count_ones(self) -> Self::Unsigned;
223
224 /// Returns the number of zeros in the binary representation of each element.
225 fn count_zeros(self) -> Self::Unsigned;
226
227 /// Returns the number of leading zeros in the binary representation of each element.
228 fn leading_zeros(self) -> Self::Unsigned;
229
230 /// Returns the number of trailing zeros in the binary representation of each element.
231 fn trailing_zeros(self) -> Self::Unsigned;
232
233 /// Returns the number of leading ones in the binary representation of each element.
234 fn leading_ones(self) -> Self::Unsigned;
235
236 /// Returns the number of trailing ones in the binary representation of each element.
237 fn trailing_ones(self) -> Self::Unsigned;
238}
239
240macro_rules! impl_trait {
241 { $($ty:ident ($unsigned:ident)),* } => {
242 $(
243 impl<const N: usize> SimdInt for Simd<$ty, N> {
244 type Mask = Mask<<$ty as SimdElement>::Mask, N>;
245 type Scalar = $ty;
246 type Unsigned = Simd<$unsigned, N>;
247 type Cast<T: SimdElement> = Simd<T, N>;
248
249 #[inline]
250 fn cast<T: SimdCast>(self) -> Self::Cast<T> {
251 // Safety: supported types are guaranteed by SimdCast
252 unsafe { core::intrinsics::simd::simd_as(self) }
253 }
254
255 #[inline]
256 fn saturating_add(self, second: Self) -> Self {
257 // Safety: `self` is a vector
258 unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
259 }
260
261 #[inline]
262 fn saturating_sub(self, second: Self) -> Self {
263 // Safety: `self` is a vector
264 unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
265 }
266
267 #[inline]
268 fn abs(self) -> Self {
269 const SHR: $ty = <$ty>::BITS as $ty - 1;
270 let m = self >> Simd::splat(SHR);
271 (self^m) - m
272 }
273
274 #[inline]
275 fn abs_diff(self, second: Self) -> Self::Unsigned {
276 let max = self.simd_max(second);
277 let min = self.simd_min(second);
278 (max - min).cast()
279 }
280
281 #[inline]
282 fn saturating_abs(self) -> Self {
283 // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
284 const SHR: $ty = <$ty>::BITS as $ty - 1;
285 let m = self >> Simd::splat(SHR);
286 (self^m).saturating_sub(m)
287 }
288
289 #[inline]
290 fn saturating_neg(self) -> Self {
291 Self::splat(0).saturating_sub(self)
292 }
293
294 #[inline]
295 fn is_positive(self) -> Self::Mask {
296 self.simd_gt(Self::splat(0))
297 }
298
299 #[inline]
300 fn is_negative(self) -> Self::Mask {
301 self.simd_lt(Self::splat(0))
302 }
303
304 #[inline]
305 fn signum(self) -> Self {
306 self.is_positive().select(
307 Self::splat(1),
308 self.is_negative().select(Self::splat(-1), Self::splat(0))
309 )
310 }
311
312 #[inline]
313 fn reduce_sum(self) -> Self::Scalar {
314 // Safety: `self` is an integer vector
315 unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
316 }
317
318 #[inline]
319 fn reduce_product(self) -> Self::Scalar {
320 // Safety: `self` is an integer vector
321 unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
322 }
323
324 #[inline]
325 fn reduce_max(self) -> Self::Scalar {
326 // Safety: `self` is an integer vector
327 unsafe { core::intrinsics::simd::simd_reduce_max(self) }
328 }
329
330 #[inline]
331 fn reduce_min(self) -> Self::Scalar {
332 // Safety: `self` is an integer vector
333 unsafe { core::intrinsics::simd::simd_reduce_min(self) }
334 }
335
336 #[inline]
337 fn reduce_and(self) -> Self::Scalar {
338 // Safety: `self` is an integer vector
339 unsafe { core::intrinsics::simd::simd_reduce_and(self) }
340 }
341
342 #[inline]
343 fn reduce_or(self) -> Self::Scalar {
344 // Safety: `self` is an integer vector
345 unsafe { core::intrinsics::simd::simd_reduce_or(self) }
346 }
347
348 #[inline]
349 fn reduce_xor(self) -> Self::Scalar {
350 // Safety: `self` is an integer vector
351 unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
352 }
353
354 #[inline]
355 fn swap_bytes(self) -> Self {
356 // Safety: `self` is an integer vector
357 unsafe { core::intrinsics::simd::simd_bswap(self) }
358 }
359
360 #[inline]
361 fn reverse_bits(self) -> Self {
362 // Safety: `self` is an integer vector
363 unsafe { core::intrinsics::simd::simd_bitreverse(self) }
364 }
365
366 #[inline]
367 fn count_ones(self) -> Self::Unsigned {
368 self.cast::<$unsigned>().count_ones()
369 }
370
371 #[inline]
372 fn count_zeros(self) -> Self::Unsigned {
373 self.cast::<$unsigned>().count_zeros()
374 }
375
376 #[inline]
377 fn leading_zeros(self) -> Self::Unsigned {
378 self.cast::<$unsigned>().leading_zeros()
379 }
380
381 #[inline]
382 fn trailing_zeros(self) -> Self::Unsigned {
383 self.cast::<$unsigned>().trailing_zeros()
384 }
385
386 #[inline]
387 fn leading_ones(self) -> Self::Unsigned {
388 self.cast::<$unsigned>().leading_ones()
389 }
390
391 #[inline]
392 fn trailing_ones(self) -> Self::Unsigned {
393 self.cast::<$unsigned>().trailing_ones()
394 }
395 }
396 )*
397 }
398}
399
400impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) }