core/portable-simd/crates/core_simd/src/simd/num/uint.rs
1use super::sealed::Sealed;
2use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd};
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 /// ```
59 fn saturating_sub(self, second: Self) -> Self;
60
61 /// Lanewise absolute difference.
62 /// Every element becomes the absolute difference of `self` and `second`.
63 ///
64 /// # Examples
65 /// ```
66 /// # #![feature(portable_simd)]
67 /// # #[cfg(feature = "as_crate")] use core_simd::simd;
68 /// # #[cfg(not(feature = "as_crate"))] use core::simd;
69 /// # use simd::prelude::*;
70 /// use core::u32::MAX;
71 /// let a = Simd::from_array([0, MAX, 100, 20]);
72 /// let b = Simd::from_array([MAX, 0, 80, 200]);
73 /// assert_eq!(a.abs_diff(b), Simd::from_array([MAX, MAX, 20, 180]));
74 /// ```
75 fn abs_diff(self, second: Self) -> Self;
76
77 /// Returns the sum of the elements of the vector, with wrapping addition.
78 fn reduce_sum(self) -> Self::Scalar;
79
80 /// Returns the product of the elements of the vector, with wrapping multiplication.
81 fn reduce_product(self) -> Self::Scalar;
82
83 /// Returns the maximum element in the vector.
84 fn reduce_max(self) -> Self::Scalar;
85
86 /// Returns the minimum element in the vector.
87 fn reduce_min(self) -> Self::Scalar;
88
89 /// Returns the cumulative bitwise "and" across the elements of the vector.
90 fn reduce_and(self) -> Self::Scalar;
91
92 /// Returns the cumulative bitwise "or" across the elements of the vector.
93 fn reduce_or(self) -> Self::Scalar;
94
95 /// Returns the cumulative bitwise "xor" across the elements of the vector.
96 fn reduce_xor(self) -> Self::Scalar;
97
98 /// Reverses the byte order of each element.
99 fn swap_bytes(self) -> Self;
100
101 /// Reverses the order of bits in each elemnent.
102 /// The least significant bit becomes the most significant bit, second least-significant bit becomes second most-significant bit, etc.
103 fn reverse_bits(self) -> Self;
104
105 /// Returns the number of ones in the binary representation of each element.
106 fn count_ones(self) -> Self;
107
108 /// Returns the number of zeros in the binary representation of each element.
109 fn count_zeros(self) -> Self;
110
111 /// Returns the number of leading zeros in the binary representation of each element.
112 fn leading_zeros(self) -> Self;
113
114 /// Returns the number of trailing zeros in the binary representation of each element.
115 fn trailing_zeros(self) -> Self;
116
117 /// Returns the number of leading ones in the binary representation of each element.
118 fn leading_ones(self) -> Self;
119
120 /// Returns the number of trailing ones in the binary representation of each element.
121 fn trailing_ones(self) -> Self;
122}
123
124macro_rules! impl_trait {
125 { $($ty:ident ($signed:ident)),* } => {
126 $(
127 impl<const N: usize> Sealed for Simd<$ty, N>
128 where
129 LaneCount<N>: SupportedLaneCount,
130 {
131 }
132
133 impl<const N: usize> SimdUint for Simd<$ty, N>
134 where
135 LaneCount<N>: SupportedLaneCount,
136 {
137 type Scalar = $ty;
138 type Cast<T: SimdElement> = Simd<T, N>;
139
140 #[inline]
141 fn cast<T: SimdCast>(self) -> Self::Cast<T> {
142 // Safety: supported types are guaranteed by SimdCast
143 unsafe { core::intrinsics::simd::simd_as(self) }
144 }
145
146 #[inline]
147 fn wrapping_neg(self) -> Self {
148 use crate::simd::num::SimdInt;
149 (-self.cast::<$signed>()).cast()
150 }
151
152 #[inline]
153 fn saturating_add(self, second: Self) -> Self {
154 // Safety: `self` is a vector
155 unsafe { core::intrinsics::simd::simd_saturating_add(self, second) }
156 }
157
158 #[inline]
159 fn saturating_sub(self, second: Self) -> Self {
160 // Safety: `self` is a vector
161 unsafe { core::intrinsics::simd::simd_saturating_sub(self, second) }
162 }
163
164 #[inline]
165 fn abs_diff(self, second: Self) -> Self {
166 let max = self.simd_max(second);
167 let min = self.simd_min(second);
168 max - min
169 }
170
171 #[inline]
172 fn reduce_sum(self) -> Self::Scalar {
173 // Safety: `self` is an integer vector
174 unsafe { core::intrinsics::simd::simd_reduce_add_ordered(self, 0) }
175 }
176
177 #[inline]
178 fn reduce_product(self) -> Self::Scalar {
179 // Safety: `self` is an integer vector
180 unsafe { core::intrinsics::simd::simd_reduce_mul_ordered(self, 1) }
181 }
182
183 #[inline]
184 fn reduce_max(self) -> Self::Scalar {
185 // Safety: `self` is an integer vector
186 unsafe { core::intrinsics::simd::simd_reduce_max(self) }
187 }
188
189 #[inline]
190 fn reduce_min(self) -> Self::Scalar {
191 // Safety: `self` is an integer vector
192 unsafe { core::intrinsics::simd::simd_reduce_min(self) }
193 }
194
195 #[inline]
196 fn reduce_and(self) -> Self::Scalar {
197 // Safety: `self` is an integer vector
198 unsafe { core::intrinsics::simd::simd_reduce_and(self) }
199 }
200
201 #[inline]
202 fn reduce_or(self) -> Self::Scalar {
203 // Safety: `self` is an integer vector
204 unsafe { core::intrinsics::simd::simd_reduce_or(self) }
205 }
206
207 #[inline]
208 fn reduce_xor(self) -> Self::Scalar {
209 // Safety: `self` is an integer vector
210 unsafe { core::intrinsics::simd::simd_reduce_xor(self) }
211 }
212
213 #[inline]
214 fn swap_bytes(self) -> Self {
215 // Safety: `self` is an integer vector
216 unsafe { core::intrinsics::simd::simd_bswap(self) }
217 }
218
219 #[inline]
220 fn reverse_bits(self) -> Self {
221 // Safety: `self` is an integer vector
222 unsafe { core::intrinsics::simd::simd_bitreverse(self) }
223 }
224
225 #[inline]
226 fn count_ones(self) -> Self {
227 // Safety: `self` is an integer vector
228 unsafe { core::intrinsics::simd::simd_ctpop(self) }
229 }
230
231 #[inline]
232 fn count_zeros(self) -> Self {
233 (!self).count_ones()
234 }
235
236 #[inline]
237 fn leading_zeros(self) -> Self {
238 // Safety: `self` is an integer vector
239 unsafe { core::intrinsics::simd::simd_ctlz(self) }
240 }
241
242 #[inline]
243 fn trailing_zeros(self) -> Self {
244 // Safety: `self` is an integer vector
245 unsafe { core::intrinsics::simd::simd_cttz(self) }
246 }
247
248 #[inline]
249 fn leading_ones(self) -> Self {
250 (!self).leading_zeros()
251 }
252
253 #[inline]
254 fn trailing_ones(self) -> Self {
255 (!self).trailing_zeros()
256 }
257 }
258 )*
259 }
260}
261
262impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) }