core_simd/simd/num/uint.rs
1use crate::simd::{Simd, SimdCast, SimdElement, cmp::SimdOrd};
2
3/// Operations on SIMD vectors of unsigned integers.
4pub impl(self) trait SimdUint: Copy {
5 /// Scalar type contained by this SIMD vector type.
6 type Scalar;
7
8 /// A SIMD vector with a different element type.
9 type Cast<T: SimdElement>;
10
11 /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
12 ///
13 /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
14 /// other integer types, and saturating to float types).
15 #[must_use]
16 fn cast<T: SimdCast>(self) -> Self::Cast<T>;
17
18 /// Wrapping negation.
19 ///
20 /// Like [`u32::wrapping_neg`], all applications of this function will wrap, with the exception
21 /// of `-0`.
22 fn wrapping_neg(self) -> Self;
23
24 /// Lanewise saturating add.
25 ///
26 /// # Examples
27 /// ```
28 /// # #![feature(portable_simd)]
29 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
30 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
31 /// # use simd::prelude::*;
32 /// use core::u32::MAX;
33 /// let x = Simd::from_array([2, 1, 0, MAX]);
34 /// let max = Simd::splat(MAX);
35 /// let unsat = x + max;
36 /// let sat = x.saturating_add(max);
37 /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
38 /// assert_eq!(sat, max);
39 /// ```
40 fn saturating_add(self, second: Self) -> Self;
41
42 /// Lanewise saturating subtract.
43 ///
44 /// # Examples
45 /// ```
46 /// # #![feature(portable_simd)]
47 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
48 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
49 /// # use simd::prelude::*;
50 /// use core::u32::MAX;
51 /// let x = Simd::from_array([2, 1, 0, MAX]);
52 /// let max = Simd::splat(MAX);
53 /// let unsat = x - max;
54 /// let sat = x.saturating_sub(max);
55 /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
56 /// assert_eq!(sat, Simd::splat(0));
57 /// ```
58 fn saturating_sub(self, second: Self) -> Self;
59
60 /// Lanewise absolute difference.
61 /// Every element becomes the absolute difference of `self` and `second`.
62 ///
63 /// # Examples
64 /// ```
65 /// # #![feature(portable_simd)]
66 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
67 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
68 /// # use simd::prelude::*;
69 /// use core::u32::MAX;
70 /// let a = Simd::from_array([0, MAX, 100, 20]);
71 /// let b = Simd::from_array([MAX, 0, 80, 200]);
72 /// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
73 /// ```
74 fn abs_diff(self, second: Self) -> Self;
75
76 /// Returns the sum of the elements of the vector, with wrapping addition.
77 fn reduce_sum(self) -> Self::Scalar;
78
79 /// Returns the product of the elements of the vector, with wrapping multiplication.
80 fn reduce_product(self) -> Self::Scalar;
81
82 /// Returns the maximum element in the vector.
83 fn reduce_max(self) -> Self::Scalar;
84
85 /// Returns the minimum element in the vector.
86 fn reduce_min(self) -> Self::Scalar;
87
88 /// Returns the cumulative bitwise "and" across the elements of the vector.
89 fn reduce_and(self) -> Self::Scalar;
90
91 /// Returns the cumulative bitwise "or" across the elements of the vector.
92 fn reduce_or(self) -> Self::Scalar;
93
94 /// Returns the cumulative bitwise "xor" across the elements of the vector.
95 fn reduce_xor(self) -> Self::Scalar;
96
97 /// Reverses the byte order of each element.
98 fn swap_bytes(self) -> Self;
99
100 /// Reverses the order of bits in each elemnent.
101 /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
102 fn reverse_bits(self) -> Self;
103
104 /// Returns the number of ones in the binary representation of each element.
105 fn count_ones(self) -> Self;
106
107 /// Returns the number of zeros in the binary representation of each element.
108 fn count_zeros(self) -> Self;
109
110 /// Returns the number of leading zeros in the binary representation of each element.
111 fn leading_zeros(self) -> Self;
112
113 /// Returns the number of trailing zeros in the binary representation of each element.
114 fn trailing_zeros(self) -> Self;
115
116 /// Returns the number of leading ones in the binary representation of each element.
117 fn leading_ones(self) -> Self;
118
119 /// Returns the number of trailing ones in the binary representation of each element.
120 fn trailing_ones(self) -> Self;
121}
122
123macro_rules! impl_trait {
124 { $($ty:ident ($signed:ident)),* } => {
125 $(
126 impl<const N: usize> SimdUint for Simd<$ty, N>
127 {
128 type Scalar = $ty;
129 type Cast<T: SimdElement> = Simd<T, N>;
130
131 #[inline]
132 fn cast<T: SimdCast>(self) -> Self::Cast<T> {
133 // Safety: supported types are guaranteed by SimdCast
134 unsafe { core::intrinsics::simd::simd_as(self) }
135 }
136
137 #[inline]
138 fn wrapping_neg(self) -> Self {
139 use crate::simd::num::SimdInt;
140 (-self.cast::<$signed>()).cast()
141 }
142
143 #[inline]
144 fn saturating_add(self, second: Self) -> Self {
145 // Safety: `self` is a vector
146 unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
147 }
148
149 #[inline]
150 fn saturating_sub(self, second: Self) -> Self {
151 // Safety: `self` is a vector
152 unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
153 }
154
155 #[inline]
156 fn abs_diff(self, second: Self) -> Self {
157 let max = self.simd_max(second);
158 let min = self.simd_min(second);
159 max - min
160 }
161
162 #[inline]
163 fn reduce_sum(self) -> Self::Scalar {
164 // Safety: `self` is an integer vector
165 unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
166 }
167
168 #[inline]
169 fn reduce_product(self) -> Self::Scalar {
170 // Safety: `self` is an integer vector
171 unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
172 }
173
174 #[inline]
175 fn reduce_max(self) -> Self::Scalar {
176 // Safety: `self` is an integer vector
177 unsafe { core::intrinsics::simd::simd_reduce_max(self) }
178 }
179
180 #[inline]
181 fn reduce_min(self) -> Self::Scalar {
182 // Safety: `self` is an integer vector
183 unsafe { core::intrinsics::simd::simd_reduce_min(self) }
184 }
185
186 #[inline]
187 fn reduce_and(self) -> Self::Scalar {
188 // Safety: `self` is an integer vector
189 unsafe { core::intrinsics::simd::simd_reduce_and(self) }
190 }
191
192 #[inline]
193 fn reduce_or(self) -> Self::Scalar {
194 // Safety: `self` is an integer vector
195 unsafe { core::intrinsics::simd::simd_reduce_or(self) }
196 }
197
198 #[inline]
199 fn reduce_xor(self) -> Self::Scalar {
200 // Safety: `self` is an integer vector
201 unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
202 }
203
204 #[inline]
205 fn swap_bytes(self) -> Self {
206 // Safety: `self` is an integer vector
207 unsafe { core::intrinsics::simd::simd_bswap(self) }
208 }
209
210 #[inline]
211 fn reverse_bits(self) -> Self {
212 // Safety: `self` is an integer vector
213 unsafe { core::intrinsics::simd::simd_bitreverse(self) }
214 }
215
216 #[inline]
217 fn count_ones(self) -> Self {
218 // Safety: `self` is an integer vector
219 unsafe { core::intrinsics::simd::simd_ctpop(self) }
220 }
221
222 #[inline]
223 fn count_zeros(self) -> Self {
224 (!self).count_ones()
225 }
226
227 #[inline]
228 fn leading_zeros(self) -> Self {
229 // Safety: `self` is an integer vector
230 unsafe { core::intrinsics::simd::simd_ctlz(self) }
231 }
232
233 #[inline]
234 fn trailing_zeros(self) -> Self {
235 // Safety: `self` is an integer vector
236 unsafe { core::intrinsics::simd::simd_cttz(self) }
237 }
238
239 #[inline]
240 fn leading_ones(self) -> Self {
241 (!self).leading_zeros()
242 }
243
244 #[inline]
245 fn trailing_ones(self) -> Self {
246 (!self).trailing_zeros()
247 }
248 }
249 )*
250 }
251}
252
253impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) }