1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
6 #[repr(C, align(16))]
7 pub struct u64x2 { pub(crate) sse: m128i }
8 } else if #[cfg(target_feature="simd128")] {
9 use core::arch::wasm32::*;
10
11 #[derive(Clone, Copy)]
12 #[repr(transparent)]
13 pub struct u64x2 { pub(crate) simd: v128 }
14
15 impl Default for u64x2 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for u64x2 {
22 fn eq(&self, other: &Self) -> bool {
23 u64x2_all_true(u64x2_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for u64x2 { }
28 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
29 use core::arch::aarch64::*;
30 #[repr(C)]
31 #[derive(Copy, Clone)]
32 pub struct u64x2 { pub(crate) neon : uint64x2_t }
33
34 impl Default for u64x2 {
35 #[inline]
36 #[must_use]
37 fn default() -> Self {
38 unsafe { Self { neon: vdupq_n_u64(0)} }
39 }
40 }
41
42 impl PartialEq for u64x2 {
43 #[inline]
44 #[must_use]
45 fn eq(&self, other: &Self) -> bool {
46 unsafe {
47 vgetq_lane_u64(self.neon,0) == vgetq_lane_u64(other.neon,0) && vgetq_lane_u64(self.neon,1) == vgetq_lane_u64(other.neon,1)
48 }
49 }
50 }
51
52 impl Eq for u64x2 { }
53 } else {
54 #[derive(Default, Clone, Copy, PartialEq, Eq)]
55 #[repr(C, align(16))]
56 pub struct u64x2 { arr: [u64;2] }
57 }
58}
59
60int_uint_consts!(u64, 2, u64x2, 128);
61
62unsafe impl Zeroable for u64x2 {}
63unsafe impl Pod for u64x2 {}
64
65impl Add for u64x2 {
66 type Output = Self;
67 #[inline]
68 #[must_use]
69 fn add(self, rhs: Self) -> Self::Output {
70 pick! {
71 if #[cfg(target_feature="sse2")] {
72 Self { sse: add_i64_m128i(self.sse, rhs.sse) }
73 } else if #[cfg(target_feature="simd128")] {
74 Self { simd: u64x2_add(self.simd, rhs.simd) }
75 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
76 unsafe { Self { neon: vaddq_u64(self.neon, rhs.neon) } }
77 } else {
78 Self { arr: [
79 self.arr[0].wrapping_add(rhs.arr[0]),
80 self.arr[1].wrapping_add(rhs.arr[1]),
81 ]}
82 }
83 }
84 }
85}
86
87impl Sub for u64x2 {
88 type Output = Self;
89 #[inline]
90 #[must_use]
91 fn sub(self, rhs: Self) -> Self::Output {
92 pick! {
93 if #[cfg(target_feature="sse2")] {
94 Self { sse: sub_i64_m128i(self.sse, rhs.sse) }
95 } else if #[cfg(target_feature="simd128")] {
96 Self { simd: u64x2_sub(self.simd, rhs.simd) }
97 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
98 unsafe { Self { neon: vsubq_u64(self.neon, rhs.neon) } }
99 } else {
100 Self { arr: [
101 self.arr[0].wrapping_sub(rhs.arr[0]),
102 self.arr[1].wrapping_sub(rhs.arr[1]),
103 ]}
104 }
105 }
106 }
107}
108
109impl Mul for u64x2 {
111 type Output = Self;
112 #[inline]
113 #[must_use]
114 fn mul(self, rhs: Self) -> Self::Output {
115 pick! {
116 if #[cfg(target_feature="simd128")] {
117 Self { simd: u64x2_mul(self.simd, rhs.simd) }
118 } else {
119 let arr1: [u64; 2] = cast(self);
120 let arr2: [u64; 2] = cast(rhs);
121 cast([
122 arr1[0].wrapping_mul(arr2[0]),
123 arr1[1].wrapping_mul(arr2[1]),
124 ])
125 }
126 }
127 }
128}
129
130impl Add<u64> for u64x2 {
131 type Output = Self;
132 #[inline]
133 #[must_use]
134 fn add(self, rhs: u64) -> Self::Output {
135 self.add(Self::splat(rhs))
136 }
137}
138
139impl Sub<u64> for u64x2 {
140 type Output = Self;
141 #[inline]
142 #[must_use]
143 fn sub(self, rhs: u64) -> Self::Output {
144 self.sub(Self::splat(rhs))
145 }
146}
147
148impl Mul<u64> for u64x2 {
149 type Output = Self;
150 #[inline]
151 #[must_use]
152 fn mul(self, rhs: u64) -> Self::Output {
153 self.mul(Self::splat(rhs))
154 }
155}
156
157impl Add<u64x2> for u64 {
158 type Output = u64x2;
159 #[inline]
160 #[must_use]
161 fn add(self, rhs: u64x2) -> Self::Output {
162 u64x2::splat(self).add(rhs)
163 }
164}
165
166impl Sub<u64x2> for u64 {
167 type Output = u64x2;
168 #[inline]
169 #[must_use]
170 fn sub(self, rhs: u64x2) -> Self::Output {
171 u64x2::splat(self).sub(rhs)
172 }
173}
174
175impl Mul<u64x2> for u64 {
176 type Output = u64x2;
177 #[inline]
178 #[must_use]
179 fn mul(self, rhs: u64x2) -> Self::Output {
180 u64x2::splat(self).mul(rhs)
181 }
182}
183
184impl BitAnd for u64x2 {
185 type Output = Self;
186 #[inline]
187 #[must_use]
188 fn bitand(self, rhs: Self) -> Self::Output {
189 pick! {
190 if #[cfg(target_feature="sse2")] {
191 Self { sse: bitand_m128i(self.sse, rhs.sse) }
192 } else if #[cfg(target_feature="simd128")] {
193 Self { simd: v128_and(self.simd, rhs.simd) }
194 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
195 unsafe {Self { neon: vandq_u64(self.neon, rhs.neon) }}
196 } else {
197 Self { arr: [
198 self.arr[0].bitand(rhs.arr[0]),
199 self.arr[1].bitand(rhs.arr[1]),
200 ]}
201 }
202 }
203 }
204}
205
206impl BitOr for u64x2 {
207 type Output = Self;
208 #[inline]
209 #[must_use]
210 fn bitor(self, rhs: Self) -> Self::Output {
211 pick! {
212 if #[cfg(target_feature="sse2")] {
213 Self { sse: bitor_m128i(self.sse, rhs.sse) }
214 } else if #[cfg(target_feature="simd128")] {
215 Self { simd: v128_or(self.simd, rhs.simd) }
216 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
217 unsafe {Self { neon: vorrq_u64(self.neon, rhs.neon) }}
218 } else {
219 Self { arr: [
220 self.arr[0].bitor(rhs.arr[0]),
221 self.arr[1].bitor(rhs.arr[1]),
222 ]}
223 }
224 }
225 }
226}
227
228impl BitXor for u64x2 {
229 type Output = Self;
230 #[inline]
231 #[must_use]
232 fn bitxor(self, rhs: Self) -> Self::Output {
233 pick! {
234 if #[cfg(target_feature="sse2")] {
235 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
236 } else if #[cfg(target_feature="simd128")] {
237 Self { simd: v128_xor(self.simd, rhs.simd) }
238 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
239 unsafe {Self { neon: veorq_u64(self.neon, rhs.neon) }}
240 } else {
241 Self { arr: [
242 self.arr[0].bitxor(rhs.arr[0]),
243 self.arr[1].bitxor(rhs.arr[1]),
244 ]}
245 }
246 }
247 }
248}
249
250macro_rules! impl_shl_t_for_u64x2 {
251 ($($shift_type:ty),+ $(,)?) => {
252 $(impl Shl<$shift_type> for u64x2 {
253 type Output = Self;
254 #[inline]
256 #[must_use]
257 fn shl(self, rhs: $shift_type) -> Self::Output {
258 pick! {
259 if #[cfg(target_feature="sse2")] {
260 let shift = cast([rhs as u64, 0]);
261 Self { sse: shl_all_u64_m128i(self.sse, shift) }
262 } else if #[cfg(target_feature="simd128")] {
263 Self { simd: u64x2_shl(self.simd, rhs as u32) }
264 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
265 unsafe {Self { neon: vshlq_u64(self.neon, vmovq_n_s64(rhs as i64)) }}
266 } else {
267 let u = rhs as u64;
268 Self { arr: [
269 self.arr[0] << u,
270 self.arr[1] << u,
271 ]}
272 }
273 }
274 }
275 })+
276 };
277}
278impl_shl_t_for_u64x2!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
279
280macro_rules! impl_shr_t_for_u64x2 {
281 ($($shift_type:ty),+ $(,)?) => {
282 $(impl Shr<$shift_type> for u64x2 {
283 type Output = Self;
284 #[inline]
286 #[must_use]
287 fn shr(self, rhs: $shift_type) -> Self::Output {
288 pick! {
289 if #[cfg(target_feature="sse2")] {
290 let shift = cast([rhs as u64, 0]);
291 Self { sse: shr_all_u64_m128i(self.sse, shift) }
292 } else if #[cfg(target_feature="simd128")] {
293 Self { simd: u64x2_shr(self.simd, rhs as u32) }
294 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
295 unsafe {Self { neon: vshlq_u64(self.neon, vmovq_n_s64(-(rhs as i64))) }}
296 } else {
297 let u = rhs as u64;
298 Self { arr: [
299 self.arr[0] >> u,
300 self.arr[1] >> u,
301 ]}
302 }
303 }
304 }
305 })+
306 };
307}
308impl_shr_t_for_u64x2!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
309
310impl u64x2 {
311 #[inline]
312 #[must_use]
313 pub const fn new(array: [u64; 2]) -> Self {
314 unsafe { core::intrinsics::transmute(array) }
315 }
316 #[inline]
317 #[must_use]
318 pub fn cmp_eq(self, rhs: Self) -> Self {
319 pick! {
320 if #[cfg(target_feature="sse4.1")] {
321 Self { sse: cmp_eq_mask_i64_m128i(self.sse, rhs.sse) }
322 } else if #[cfg(target_feature="simd128")] {
323 Self { simd: u64x2_eq(self.simd, rhs.simd) }
324 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
325 unsafe {Self { neon: vceqq_u64(self.neon, rhs.neon) } }
326 } else {
327 let s: [u64;2] = cast(self);
328 let r: [u64;2] = cast(rhs);
329 cast([
330 if s[0] == r[0] { -1_i64 } else { 0 },
331 if s[1] == r[1] { -1_i64 } else { 0 },
332 ])
333 }
334 }
335 }
336 #[inline]
337 #[must_use]
338 pub fn cmp_gt(self, rhs: Self) -> Self {
339 pick! {
340 if #[cfg(target_feature="sse4.2")] {
341 let highbit = u64x2::splat(1 << 63);
343 Self { sse: cmp_gt_mask_i64_m128i((self ^ highbit).sse, (rhs ^ highbit).sse) }
344 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
345 unsafe {Self { neon: vcgtq_u64(self.neon, rhs.neon) }}
346 } else {
347 let s: [u64;2] = cast(self);
349 let r: [u64;2] = cast(rhs);
350 cast([
351 if s[0] > r[0] { u64::MAX } else { 0 },
352 if s[1] > r[1] { u64::MAX } else { 0 },
353 ])
354 }
355 }
356 }
357
358 #[inline]
359 #[must_use]
360 pub fn cmp_lt(self, rhs: Self) -> Self {
361 rhs.cmp_gt(self)
363 }
364
365 #[inline]
366 #[must_use]
367 pub fn blend(self, t: Self, f: Self) -> Self {
368 pick! {
369 if #[cfg(target_feature="sse4.1")] {
370 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
371 } else if #[cfg(target_feature="simd128")] {
372 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
373 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
374 unsafe {Self { neon: vbslq_u64(self.neon, t.neon, f.neon) }}
375 } else {
376 generic_bit_blend(self, t, f)
377 }
378 }
379 }
380
381 #[inline]
382 pub fn to_array(self) -> [u64; 2] {
383 cast(self)
384 }
385
386 #[inline]
387 pub fn as_array_ref(&self) -> &[u64; 2] {
388 cast_ref(self)
389 }
390
391 #[inline]
392 pub fn as_array_mut(&mut self) -> &mut [u64; 2] {
393 cast_mut(self)
394 }
395}