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