core_simd/simd/num/int.rs
1use super::sealed::Sealed;
2use crate::simd::{
3 Mask, Select, Simd, SimdCast, SimdElement, cmp::SimdOrd, cmp::SimdPartialOrd, num::SimdUint,
4};
5
6/// Operations on SIMD vectors of signed integers.
7pub trait SimdInt: Copy + Sealed {
8 /// Mask type used for manipulating this SIMD vector type.
9 type Mask;
10
11 /// Scalar type contained by this SIMD vector type.
12 type Scalar;
13
14 /// A SIMD vector of unsigned integers with the same element size.
15 type Unsigned;
16
17 /// A SIMD vector with a different element type.
18 type Cast<T: SimdElement>;
19
20 /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
21 ///
22 /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
23 /// other integer types, and saturating to float types).
24 #[must_use]
25 fn cast<T: SimdCast>(self) -> Self::Cast<T>;
26
27 /// Lanewise saturating add.
28 ///
29 /// # Examples
30 /// ```
31 /// # #![feature(portable_simd)]
32 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
33 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
34 /// # use simd::prelude::*;
35 /// use core::i32::{MIN, MAX};
36 /// let x = Simd::from_array([MIN, 0, 1, MAX]);
37 /// let max = Simd::splat(MAX);
38 /// let unsat = x + max;
39 /// let sat = x.saturating_add(max);
40 /// assert_eq!(unsat, Simd::from_array([-1, MAX, MIN, -2]));
41 /// assert_eq!(sat, Simd::from_array([-1, MAX, MAX, MAX]));
42 /// ```
43 fn saturating_add(self, second: Self) -> Self;
44
45 /// Lanewise saturating subtract.
46 ///
47 /// # Examples
48 /// ```
49 /// # #![feature(portable_simd)]
50 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
51 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
52 /// # use simd::prelude::*;
53 /// use core::i32::{MIN, MAX};
54 /// let x = Simd::from_array([MIN, -2, -1, MAX]);
55 /// let max = Simd::splat(MAX);
56 /// let unsat = x - max;
57 /// let sat = x.saturating_sub(max);
58 /// assert_eq!(unsat, Simd::from_array([1, MAX, MIN, 0]));
59 /// assert_eq!(sat, Simd::from_array([MIN, MIN, MIN, 0]));
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> Sealed for Simd<$ty, N> {}
244
245 impl<const N: usize> SimdInt for Simd<$ty, N> {
246 type Mask = Mask<<$ty as SimdElement>::Mask, N>;
247 type Scalar = $ty;
248 type Unsigned = Simd<$unsigned, N>;
249 type Cast<T: SimdElement> = Simd<T, N>;
250
251 #[inline]
252 fn cast<T: SimdCast>(self) -> Self::Cast<T> {
253 // Safety: supported types are guaranteed by SimdCast
254 unsafe { core::intrinsics::simd::simd_as(self) }
255 }
256
257 #[inline]
258 fn saturating_add(self, second: Self) -> Self {
259 // Safety: `self` is a vector
260 unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
261 }
262
263 #[inline]
264 fn saturating_sub(self, second: Self) -> Self {
265 // Safety: `self` is a vector
266 unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
267 }
268
269 #[inline]
270 fn abs(self) -> Self {
271 const SHR: $ty = <$ty>::BITS as $ty - 1;
272 let m = self >> Simd::splat(SHR);
273 (self^m) - m
274 }
275
276 #[inline]
277 fn abs_diff(self, second: Self) -> Self::Unsigned {
278 let max = self.simd_max(second);
279 let min = self.simd_min(second);
280 (max - min).cast()
281 }
282
283 #[inline]
284 fn saturating_abs(self) -> Self {
285 // arith shift for -1 or 0 mask based on sign bit, giving 2s complement
286 const SHR: $ty = <$ty>::BITS as $ty - 1;
287 let m = self >> Simd::splat(SHR);
288 (self^m).saturating_sub(m)
289 }
290
291 #[inline]
292 fn saturating_neg(self) -> Self {
293 Self::splat(0).saturating_sub(self)
294 }
295
296 #[inline]
297 fn is_positive(self) -> Self::Mask {
298 self.simd_gt(Self::splat(0))
299 }
300
301 #[inline]
302 fn is_negative(self) -> Self::Mask {
303 self.simd_lt(Self::splat(0))
304 }
305
306 #[inline]
307 fn signum(self) -> Self {
308 self.is_positive().select(
309 Self::splat(1),
310 self.is_negative().select(Self::splat(-1), Self::splat(0))
311 )
312 }
313
314 #[inline]
315 fn reduce_sum(self) -> Self::Scalar {
316 // Safety: `self` is an integer vector
317 unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
318 }
319
320 #[inline]
321 fn reduce_product(self) -> Self::Scalar {
322 // Safety: `self` is an integer vector
323 unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
324 }
325
326 #[inline]
327 fn reduce_max(self) -> Self::Scalar {
328 // Safety: `self` is an integer vector
329 unsafe { core::intrinsics::simd::simd_reduce_max(self) }
330 }
331
332 #[inline]
333 fn reduce_min(self) -> Self::Scalar {
334 // Safety: `self` is an integer vector
335 unsafe { core::intrinsics::simd::simd_reduce_min(self) }
336 }
337
338 #[inline]
339 fn reduce_and(self) -> Self::Scalar {
340 // Safety: `self` is an integer vector
341 unsafe { core::intrinsics::simd::simd_reduce_and(self) }
342 }
343
344 #[inline]
345 fn reduce_or(self) -> Self::Scalar {
346 // Safety: `self` is an integer vector
347 unsafe { core::intrinsics::simd::simd_reduce_or(self) }
348 }
349
350 #[inline]
351 fn reduce_xor(self) -> Self::Scalar {
352 // Safety: `self` is an integer vector
353 unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
354 }
355
356 #[inline]
357 fn swap_bytes(self) -> Self {
358 // Safety: `self` is an integer vector
359 unsafe { core::intrinsics::simd::simd_bswap(self) }
360 }
361
362 #[inline]
363 fn reverse_bits(self) -> Self {
364 // Safety: `self` is an integer vector
365 unsafe { core::intrinsics::simd::simd_bitreverse(self) }
366 }
367
368 #[inline]
369 fn count_ones(self) -> Self::Unsigned {
370 self.cast::<$unsigned>().count_ones()
371 }
372
373 #[inline]
374 fn count_zeros(self) -> Self::Unsigned {
375 self.cast::<$unsigned>().count_zeros()
376 }
377
378 #[inline]
379 fn leading_zeros(self) -> Self::Unsigned {
380 self.cast::<$unsigned>().leading_zeros()
381 }
382
383 #[inline]
384 fn trailing_zeros(self) -> Self::Unsigned {
385 self.cast::<$unsigned>().trailing_zeros()
386 }
387
388 #[inline]
389 fn leading_ones(self) -> Self::Unsigned {
390 self.cast::<$unsigned>().leading_ones()
391 }
392
393 #[inline]
394 fn trailing_ones(self) -> Self::Unsigned {
395 self.cast::<$unsigned>().trailing_ones()
396 }
397 }
398 )*
399 }
400}
401
402impl_trait! { i8 (u8), i16 (u16), i32 (u32), i64 (u64), isize (usize) }