1 | use super::sealed::Sealed; |
2 | use crate::simd::{LaneCount, Simd, SimdCast, SimdElement, SupportedLaneCount}; |
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 | /// 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 | |
101 | macro_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 { core::intrinsics::simd::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 { core::intrinsics::simd::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 { core::intrinsics::simd::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 { core::intrinsics::simd::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 { core::intrinsics::simd::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 { core::intrinsics::simd::simd_reduce_max(self) } |
157 | } |
158 | |
159 | #[inline] |
160 | fn reduce_min(self) -> Self::Scalar { |
161 | // Safety: `self` is an integer vector |
162 | unsafe { core::intrinsics::simd::simd_reduce_min(self) } |
163 | } |
164 | |
165 | #[inline] |
166 | fn reduce_and(self) -> Self::Scalar { |
167 | // Safety: `self` is an integer vector |
168 | unsafe { core::intrinsics::simd::simd_reduce_and(self) } |
169 | } |
170 | |
171 | #[inline] |
172 | fn reduce_or(self) -> Self::Scalar { |
173 | // Safety: `self` is an integer vector |
174 | unsafe { core::intrinsics::simd::simd_reduce_or(self) } |
175 | } |
176 | |
177 | #[inline] |
178 | fn reduce_xor(self) -> Self::Scalar { |
179 | // Safety: `self` is an integer vector |
180 | unsafe { core::intrinsics::simd::simd_reduce_xor(self) } |
181 | } |
182 | |
183 | #[inline] |
184 | fn swap_bytes(self) -> Self { |
185 | // Safety: `self` is an integer vector |
186 | unsafe { core::intrinsics::simd::simd_bswap(self) } |
187 | } |
188 | |
189 | #[inline] |
190 | fn reverse_bits(self) -> Self { |
191 | // Safety: `self` is an integer vector |
192 | unsafe { core::intrinsics::simd::simd_bitreverse(self) } |
193 | } |
194 | |
195 | #[inline] |
196 | fn leading_zeros(self) -> Self { |
197 | // Safety: `self` is an integer vector |
198 | unsafe { core::intrinsics::simd::simd_ctlz(self) } |
199 | } |
200 | |
201 | #[inline] |
202 | fn trailing_zeros(self) -> Self { |
203 | // Safety: `self` is an integer vector |
204 | unsafe { core::intrinsics::simd::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 | |
221 | impl_trait! { u8 (i8), u16 (i16), u32 (i32), u64 (i64), usize (isize) } |
222 | |