1 | use super::sealed::Sealed; |
2 | use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount, cmp::SimdOrd}; |
3 | |
4 | /// Operations on SIMD vectors of unsigned integers. |
5 | pub 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 | |
123 | macro_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 | |
261 | impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) } |
262 | |