core/portable-simd/crates/core_simd/src/simd/num/uint.rs
1use super::sealed::Sealed;
2use crate::simd::{cmp::SimdOrd, LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount};
3
4/// Operations on SIMD vectors of unsigned integers.
5pub trait SimdUint: Copy + Sealed {
6 /// Scalar type contained by this SIMD vector type.
7 type Scalar;
8
9 /// A SIMD vector with a different element type.
10 type Cast<T: SimdElement>;
11
12 /// Performs elementwise conversion of this vector's elements to another SIMD-valid type.
13 ///
14 /// This follows the semantics of Rust's `as` conversion for casting integers (wrapping to
15 /// other integer types, and saturating to float types).
16 #[must_use]
17 fn cast<T: SimdCast>(self) -> Self::Cast<T>;
18
19 /// Wrapping negation.
20 ///
21 /// Like [`u32::wrapping_neg`], all applications of this function will wrap, with the exception
22 /// of `-0`.
23 fn wrapping_neg(self) -> Self;
24
25 /// Lanewise saturating add.
26 ///
27 /// # Examples
28 /// ```
29 /// # #![feature(portable_simd)]
30 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
31 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
32 /// # use simd::prelude::*;
33 /// use core::u32::MAX;
34 /// let x = Simd::from_array([2, 1, 0, MAX]);
35 /// let max = Simd::splat(MAX);
36 /// let unsat = x + max;
37 /// let sat = x.saturating_add(max);
38 /// assert_eq!(unsat, Simd::from_array([1, 0, MAX, MAX - 1]));
39 /// assert_eq!(sat, max);
40 /// ```
41 fn saturating_add(self, second: Self) -> Self;
42
43 /// Lanewise saturating subtract.
44 ///
45 /// # Examples
46 /// ```
47 /// # #![feature(portable_simd)]
48 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
49 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
50 /// # use simd::prelude::*;
51 /// use core::u32::MAX;
52 /// let x = Simd::from_array([2, 1, 0, MAX]);
53 /// let max = Simd::splat(MAX);
54 /// let unsat = x - max;
55 /// let sat = x.saturating_sub(max);
56 /// assert_eq!(unsat, Simd::from_array([3, 2, 1, 0]));
57 /// assert_eq!(sat, Simd::splat(0));
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> Sealed for Simd<$ty, N>
127 where
128 LaneCount<N>: SupportedLaneCount,
129 {
130 }
131
132 impl<const N: usize> SimdUint for Simd<$ty, N>
133 where
134 LaneCount<N>: SupportedLaneCount,
135 {
136 type Scalar = $ty;
137 type Cast<T: SimdElement> = Simd<T, N>;
138
139 #[inline]
140 fn cast<T: SimdCast>(self) -> Self::Cast<T> {
141 // Safety: supported types are guaranteed by SimdCast
142 unsafe { core::intrinsics::simd::simd_as(self) }
143 }
144
145 #[inline]
146 fn wrapping_neg(self) -> Self {
147 use crate::simd::num::SimdInt;
148 (-self.cast::<$signed>()).cast()
149 }
150
151 #[inline]
152 fn saturating_add(self, second: Self) -> Self {
153 // Safety: `self` is a vector
154 unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
155 }
156
157 #[inline]
158 fn saturating_sub(self, second: Self) -> Self {
159 // Safety: `self` is a vector
160 unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
161 }
162
163 #[inline]
164 fn abs_diff(self, second: Self) -> Self {
165 let max = self.simd_max(second);
166 let min = self.simd_min(second);
167 max - min
168 }
169
170 #[inline]
171 fn reduce_sum(self) -> Self::Scalar {
172 // Safety: `self` is an integer vector
173 unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
174 }
175
176 #[inline]
177 fn reduce_product(self) -> Self::Scalar {
178 // Safety: `self` is an integer vector
179 unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
180 }
181
182 #[inline]
183 fn reduce_max(self) -> Self::Scalar {
184 // Safety: `self` is an integer vector
185 unsafe { core::intrinsics::simd::simd_reduce_max(self) }
186 }
187
188 #[inline]
189 fn reduce_min(self) -> Self::Scalar {
190 // Safety: `self` is an integer vector
191 unsafe { core::intrinsics::simd::simd_reduce_min(self) }
192 }
193
194 #[inline]
195 fn reduce_and(self) -> Self::Scalar {
196 // Safety: `self` is an integer vector
197 unsafe { core::intrinsics::simd::simd_reduce_and(self) }
198 }
199
200 #[inline]
201 fn reduce_or(self) -> Self::Scalar {
202 // Safety: `self` is an integer vector
203 unsafe { core::intrinsics::simd::simd_reduce_or(self) }
204 }
205
206 #[inline]
207 fn reduce_xor(self) -> Self::Scalar {
208 // Safety: `self` is an integer vector
209 unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
210 }
211
212 #[inline]
213 fn swap_bytes(self) -> Self {
214 // Safety: `self` is an integer vector
215 unsafe { core::intrinsics::simd::simd_bswap(self) }
216 }
217
218 #[inline]
219 fn reverse_bits(self) -> Self {
220 // Safety: `self` is an integer vector
221 unsafe { core::intrinsics::simd::simd_bitreverse(self) }
222 }
223
224 #[inline]
225 fn count_ones(self) -> Self {
226 // Safety: `self` is an integer vector
227 unsafe { core::intrinsics::simd::simd_ctpop(self) }
228 }
229
230 #[inline]
231 fn count_zeros(self) -> Self {
232 (!self).count_ones()
233 }
234
235 #[inline]
236 fn leading_zeros(self) -> Self {
237 // Safety: `self` is an integer vector
238 unsafe { core::intrinsics::simd::simd_ctlz(self) }
239 }
240
241 #[inline]
242 fn trailing_zeros(self) -> Self {
243 // Safety: `self` is an integer vector
244 unsafe { core::intrinsics::simd::simd_cttz(self) }
245 }
246
247 #[inline]
248 fn leading_ones(self) -> Self {
249 (!self).leading_zeros()
250 }
251
252 #[inline]
253 fn trailing_ones(self) -> Self {
254 (!self).trailing_zeros()
255 }
256 }
257 )*
258 }
259}
260
261impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) }