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