1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx512f")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
6 #[repr(C, align(64))]
7 pub struct u64x8 { pub(crate) avx512: m512i }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq, Eq)]
10 #[repr(C, align(64))]
11 pub struct u64x8 { pub(crate) a : u64x4, pub(crate) b : u64x4 }
12 }
13}
14
15int_uint_consts!(u64, 8, u64x8, 512);
16
17unsafe impl Zeroable for u64x8 {}
18unsafe impl Pod for u64x8 {}
19
20impl AlignTo for u64x8 {
21 type Elem = u64;
22}
23
24impl Add for u64x8 {
25 type Output = Self;
26 #[inline]
27 fn add(self, rhs: Self) -> Self::Output {
28 pick! {
29 if #[cfg(target_feature="avx512f")] {
30 Self { avx512: add_i64_m512i(self.avx512, rhs.avx512) }
31 } else {
32 Self {
33 a : self.a.add(rhs.a),
34 b : self.b.add(rhs.b),
35 }
36 }
37 }
38 }
39}
40
41impl Sub for u64x8 {
42 type Output = Self;
43 #[inline]
44 fn sub(self, rhs: Self) -> Self::Output {
45 pick! {
46 if #[cfg(target_feature="avx512f")] {
47 Self { avx512: sub_i64_m512i(self.avx512, rhs.avx512) }
48 } else {
49 Self {
50 a : self.a.sub(rhs.a),
51 b : self.b.sub(rhs.b),
52 }
53 }
54 }
55 }
56}
57
58impl Mul for u64x8 {
59 type Output = Self;
60 #[inline]
61 fn mul(self, rhs: Self) -> Self::Output {
62 pick! {
63 if #[cfg(target_feature="avx512f")] {
64 let arr1: [u64; 8] = cast(self);
65 let arr2: [u64; 8] = cast(rhs);
66 cast([
67 arr1[0].wrapping_mul(arr2[0]),
68 arr1[1].wrapping_mul(arr2[1]),
69 arr1[2].wrapping_mul(arr2[2]),
70 arr1[3].wrapping_mul(arr2[3]),
71 arr1[4].wrapping_mul(arr2[4]),
72 arr1[5].wrapping_mul(arr2[5]),
73 arr1[6].wrapping_mul(arr2[6]),
74 arr1[7].wrapping_mul(arr2[7]),
75 ])
76 } else {
77 Self { a: self.a.mul(rhs.a), b: self.b.mul(rhs.b) }
78 }
79 }
80 }
81}
82
83integer_impl_div_rem!(u64, u64x8, [0, 1, 2, 3, 4, 5, 6, 7]);
84
85impl Add<u64> for u64x8 {
86 type Output = Self;
87 #[inline]
88 fn add(self, rhs: u64) -> Self::Output {
89 self.add(Self::splat(rhs))
90 }
91}
92
93impl Sub<u64> for u64x8 {
94 type Output = Self;
95 #[inline]
96 fn sub(self, rhs: u64) -> Self::Output {
97 self.sub(Self::splat(rhs))
98 }
99}
100
101impl Mul<u64> for u64x8 {
102 type Output = Self;
103 #[inline]
104 fn mul(self, rhs: u64) -> Self::Output {
105 self.mul(Self::splat(rhs))
106 }
107}
108
109impl Add<u64x8> for u64 {
110 type Output = u64x8;
111 #[inline]
112 fn add(self, rhs: u64x8) -> Self::Output {
113 u64x8::splat(self).add(rhs)
114 }
115}
116
117impl Sub<u64x8> for u64 {
118 type Output = u64x8;
119 #[inline]
120 fn sub(self, rhs: u64x8) -> Self::Output {
121 u64x8::splat(self).sub(rhs)
122 }
123}
124
125impl Mul<u64x8> for u64 {
126 type Output = u64x8;
127 #[inline]
128 fn mul(self, rhs: u64x8) -> Self::Output {
129 u64x8::splat(self).mul(rhs)
130 }
131}
132
133impl BitAnd for u64x8 {
134 type Output = Self;
135 #[inline]
136 fn bitand(self, rhs: Self) -> Self::Output {
137 pick! {
138 if #[cfg(target_feature="avx512f")] {
139 Self { avx512: bitand_m512i(self.avx512, rhs.avx512) }
140 } else {
141 Self {
142 a : self.a.bitand(rhs.a),
143 b : self.b.bitand(rhs.b),
144 }
145 }
146 }
147 }
148}
149
150impl BitOr for u64x8 {
151 type Output = Self;
152 #[inline]
153 fn bitor(self, rhs: Self) -> Self::Output {
154 pick! {
155 if #[cfg(target_feature="avx512f")] {
156 Self { avx512: bitor_m512i(self.avx512, rhs.avx512) }
157 } else {
158 Self {
159 a : self.a.bitor(rhs.a),
160 b : self.b.bitor(rhs.b),
161 }
162 }
163 }
164 }
165}
166
167impl BitXor for u64x8 {
168 type Output = Self;
169 #[inline]
170 fn bitxor(self, rhs: Self) -> Self::Output {
171 pick! {
172 if #[cfg(target_feature="avx512f")] {
173 Self { avx512: bitxor_m512i(self.avx512, rhs.avx512) }
174 } else {
175 Self {
176 a : self.a.bitxor(rhs.a),
177 b : self.b.bitxor(rhs.b),
178 }
179 }
180 }
181 }
182}
183
184macro_rules! impl_shl_t_for_u64x8 {
185 ($($shift_type:ty),+ $(,)?) => {
186 $(impl Shl<$shift_type> for u64x8 {
187 type Output = Self;
188 #[inline]
190 fn shl(self, rhs: $shift_type) -> Self::Output {
191 pick! {
192 if #[cfg(target_feature="avx512f")] {
193 let shift = cast(rhs as u64);
194 Self { avx512: shl_all_u64_m512i(self.avx512, shift) }
195 } else {
196 Self {
197 a : self.a.shl(rhs),
198 b : self.b.shl(rhs),
199 }
200 }
201 }
202 }
203 })+
204 };
205}
206impl_shl_t_for_u64x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
207
208macro_rules! impl_shr_t_for_u64x8 {
209 ($($shift_type:ty),+ $(,)?) => {
210 $(impl Shr<$shift_type> for u64x8 {
211 type Output = Self;
212 #[inline]
214 fn shr(self, rhs: $shift_type) -> Self::Output {
215 pick! {
216 if #[cfg(target_feature="avx512f")] {
217 let shift = cast(rhs as u64);
218 Self { avx512: shr_all_u64_m512i(self.avx512, shift) }
219 } else {
220 Self {
221 a : self.a.shr(rhs),
222 b : self.b.shr(rhs),
223 }
224 }
225 }
226 }
227 })+
228 };
229}
230impl_shr_t_for_u64x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
231
232impl Shr for u64x8 {
233 type Output = Self;
234
235 #[inline]
236 fn shr(self, rhs: Self) -> Self::Output {
237 pick! {
238 if #[cfg(target_feature="avx512f")] {
239 Self { avx512: shr_each_u64_m512i(self.avx512, rhs.avx512) }
240 } else {
241 Self {
242 a : self.a.shr(rhs.a),
243 b : self.b.shr(rhs.b),
244 }
245 }
246 }
247 }
248}
249
250impl Shl for u64x8 {
251 type Output = Self;
252
253 #[inline]
254 fn shl(self, rhs: Self) -> Self::Output {
255 pick! {
256 if #[cfg(target_feature="avx512f")] {
257 Self { avx512: shl_each_u64_m512i(self.avx512, rhs.avx512) }
258 } else {
259 Self {
260 a : self.a.shl(rhs.a),
261 b : self.b.shl(rhs.b),
262 }
263 }
264 }
265 }
266}
267
268#[expect(deprecated)]
269impl CmpEq for u64x8 {
270 type Output = Self;
271 #[inline]
272 fn simd_eq(self, rhs: Self) -> Self::Output {
273 pick! {
274 if #[cfg(target_feature="avx512f")] {
275 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Eq)}>(self.avx512, rhs.avx512) }
276 } else {
277 Self {
278 a : self.a.simd_eq(rhs.a),
279 b : self.b.simd_eq(rhs.b),
280 }
281 }
282 }
283 }
284}
285
286#[expect(deprecated)]
287impl CmpGt for u64x8 {
288 type Output = Self;
289 #[inline]
290 fn simd_gt(self, rhs: Self) -> Self::Output {
291 pick! {
292 if #[cfg(target_feature="avx512f")] {
293 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Nle)}>(self.avx512, rhs.avx512) }
294 } else {
295 Self {
296 a : self.a.simd_gt(rhs.a),
297 b : self.b.simd_gt(rhs.b),
298 }
299 }
300 }
301 }
302}
303
304#[expect(deprecated)]
305impl CmpLt for u64x8 {
306 type Output = Self;
307 #[inline]
308 fn simd_lt(self, rhs: Self) -> Self::Output {
309 pick! {
310 if #[cfg(target_feature="avx512f")] {
311 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Lt)}>(self.avx512, rhs.avx512) }
312 } else {
313 Self {
314 a : self.a.simd_lt(rhs.a),
315 b : self.b.simd_lt(rhs.b),
316 }
317 }
318 }
319 }
320}
321
322#[expect(deprecated)]
323impl CmpNe for u64x8 {
324 type Output = Self;
325 #[inline]
326 fn simd_ne(self, rhs: Self) -> Self::Output {
327 pick! {
328 if #[cfg(target_feature="avx512f")] {
329 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Ne)}>(self.avx512, rhs.avx512) }
330 } else {
331 Self {
332 a : self.a.simd_ne(rhs.a),
333 b : self.b.simd_ne(rhs.b),
334 }
335 }
336 }
337 }
338}
339
340#[expect(deprecated)]
341impl CmpLe for u64x8 {
342 type Output = Self;
343 #[inline]
344 fn simd_le(self, rhs: Self) -> Self::Output {
345 pick! {
346 if #[cfg(target_feature="avx512f")] {
347 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Le)}>(self.avx512, rhs.avx512) }
348 } else {
349 Self {
350 a : self.a.simd_le(rhs.a),
351 b : self.b.simd_le(rhs.b),
352 }
353 }
354 }
355 }
356}
357
358#[expect(deprecated)]
359impl CmpGe for u64x8 {
360 type Output = Self;
361 #[inline]
362 fn simd_ge(self, rhs: Self) -> Self::Output {
363 pick! {
364 if #[cfg(target_feature="avx512f")] {
365 Self { avx512: cmp_op_mask_u64_m512i::<{cmp_int_op!(Nlt)}>(self.avx512, rhs.avx512) }
366 } else {
367 Self {
368 a : self.a.simd_ge(rhs.a),
369 b : self.b.simd_ge(rhs.b),
370 }
371 }
372 }
373 }
374}
375
376impl u64x8 {
377 #[inline]
378 #[must_use]
379 pub const fn new(array: [u64; 8]) -> Self {
380 unsafe { core::mem::transmute(array) }
381 }
382
383 simd_comparison_fns!();
384
385 #[inline]
386 #[must_use]
387 pub fn blend(self, t: Self, f: Self) -> Self {
388 pick! {
389 if #[cfg(target_feature="avx512f")] {
390 Self { avx512: blend_varying_i8_m512i(f.avx512,t.avx512,movepi8_mask_m512i(self.avx512)) }
391 } else {
392 Self {
393 a : self.a.blend(t.a, f.a),
394 b : self.b.blend(t.b, f.b),
395 }
396 }
397 }
398 }
399
400 #[inline]
401 #[must_use]
402 pub fn reduce_add(self) -> u64 {
403 let array: [u64x4; 2] = cast(self);
404 (array[0] + array[1]).reduce_add()
405 }
406
407 #[inline]
408 #[must_use]
409 pub fn reduce_max(self) -> u64 {
410 let array: [u64x4; 2] = cast(self);
411 array[0].max(array[1]).reduce_max()
412 }
413
414 #[inline]
415 #[must_use]
416 pub fn reduce_min(self) -> u64 {
417 let array: [u64x4; 2] = cast(self);
418 array[0].min(array[1]).reduce_min()
419 }
420
421 #[inline]
422 #[must_use]
423 #[doc(alias("movemask", "move_mask"))]
424 pub fn to_bitmask(self) -> u32 {
425 i64x8::to_bitmask(cast(self))
426 }
427
428 #[inline]
429 #[must_use]
430 pub fn any(self) -> bool {
431 i64x8::any(cast(self))
432 }
433
434 #[inline]
435 #[must_use]
436 pub fn all(self) -> bool {
437 i64x8::all(cast(self))
438 }
439
440 #[inline]
441 #[must_use]
442 pub fn none(self) -> bool {
443 !self.any()
444 }
445
446 #[must_use]
448 #[inline]
449 pub fn transpose(data: [u64x8; 8]) -> [u64x8; 8] {
450 cast(i64x8::transpose(cast(data)))
451 }
452
453 #[inline]
454 pub fn to_array(self) -> [u64; 8] {
455 cast(self)
456 }
457
458 #[inline]
459 pub fn as_array(&self) -> &[u64; 8] {
460 cast_ref(self)
461 }
462
463 #[inline]
464 pub fn as_mut_array(&mut self) -> &mut [u64; 8] {
465 cast_mut(self)
466 }
467
468 #[inline]
469 #[must_use]
470 pub fn min(self, rhs: Self) -> Self {
471 pick! {
472 if #[cfg(target_feature="avx512f")] {
473 Self { avx512: min_u64_m512i(self.avx512, rhs.avx512) }
474 } else {
475 Self {
476 a: self.a.min(rhs.a),
477 b: self.b.min(rhs.b),
478 }
479 }
480 }
481 }
482
483 #[inline]
484 #[must_use]
485 pub fn max(self, rhs: Self) -> Self {
486 pick! {
487 if #[cfg(target_feature="avx512f")] {
488 Self { avx512: max_u64_m512i(self.avx512, rhs.avx512) }
489 } else {
490 Self {
491 a: self.a.max(rhs.a),
492 b: self.b.max(rhs.b),
493 }
494 }
495 }
496 }
497
498 integer_fn_clamp!();
499
500 #[inline]
501 #[must_use]
502 pub fn saturating_add(self, rhs: Self) -> Self {
503 pick! {
504 if #[cfg(target_feature="avx512f")] {
505 let result = self + rhs;
506 result.simd_lt(self).blend(Self::MAX, result)
507 } else {
508 Self {
509 a: self.a.saturating_add(rhs.a),
510 b: self.b.saturating_add(rhs.b),
511 }
512 }
513 }
514 }
515
516 #[inline]
517 #[must_use]
518 pub fn saturating_sub(self, rhs: Self) -> Self {
519 pick! {
520 if #[cfg(target_feature="avx512f")] {
521 let result = self - rhs;
522 result.simd_gt(self).blend(Self::MIN, result)
523 } else {
524 Self {
525 a: self.a.saturating_sub(rhs.a),
526 b: self.b.saturating_sub(rhs.b),
527 }
528 }
529 }
530 }
531
532 #[inline]
534 #[must_use]
535 pub fn saturating_mul(self, rhs: Self) -> Self {
536 let self_array = self.to_array();
537 let rhs_array = rhs.to_array();
538
539 Self::new([
540 self_array[0].saturating_mul(rhs_array[0]),
541 self_array[1].saturating_mul(rhs_array[1]),
542 self_array[2].saturating_mul(rhs_array[2]),
543 self_array[3].saturating_mul(rhs_array[3]),
544 self_array[4].saturating_mul(rhs_array[4]),
545 self_array[5].saturating_mul(rhs_array[5]),
546 self_array[6].saturating_mul(rhs_array[6]),
547 self_array[7].saturating_mul(rhs_array[7]),
548 ])
549 }
550
551 integer_fn_saturating_div!([0, 1, 2, 3, 4, 5, 6, 7]);
552
553 #[inline]
554 #[must_use]
555 pub fn mul_keep_high(self, rhs: Self) -> Self {
556 pick! {
557 if #[cfg(target_feature="avx512f")] {
558 let arr1: [u64; 8] = cast(self);
559 let arr2: [u64; 8] = cast(rhs);
560 cast([
561 (arr1[0] as u128 * arr2[0] as u128 >> 64) as u64,
562 (arr1[1] as u128 * arr2[1] as u128 >> 64) as u64,
563 (arr1[2] as u128 * arr2[2] as u128 >> 64) as u64,
564 (arr1[3] as u128 * arr2[3] as u128 >> 64) as u64,
565 (arr1[4] as u128 * arr2[4] as u128 >> 64) as u64,
566 (arr1[5] as u128 * arr2[5] as u128 >> 64) as u64,
567 (arr1[6] as u128 * arr2[6] as u128 >> 64) as u64,
568 (arr1[7] as u128 * arr2[7] as u128 >> 64) as u64,
569 ])
570 } else {
571 Self {
572 a: self.a.mul_keep_high(rhs.a),
573 b: self.b.mul_keep_high(rhs.b),
574 }
575 }
576 }
577 }
578}
579
580impl Not for u64x8 {
581 type Output = Self;
582 #[inline]
583 fn not(self) -> Self::Output {
584 pick! {
585 if #[cfg(target_feature="avx512f")] {
586 Self { avx512: bitxor_m512i(self.avx512, set_splat_i64_m512i(-1)) }
587 } else {
588 Self {
589 a : self.a.not(),
590 b : self.b.not(),
591 }
592 }
593 }
594 }
595}