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 i64x8 { pub(crate) avx512: m512i }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq, Eq)]
10 #[repr(C, align(64))]
11 pub struct i64x8 { pub(crate) a : i64x4, pub(crate) b : i64x4 }
12 }
13}
14
15int_uint_consts!(i64, 8, i64x8, 512);
16
17unsafe impl Zeroable for i64x8 {}
18unsafe impl Pod for i64x8 {}
19
20impl AlignTo for i64x8 {
21 type Elem = i64;
22}
23
24impl Add for i64x8 {
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 i64x8 {
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 i64x8 {
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: [i64; 8] = cast(self);
65 let arr2: [i64; 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!(i64, i64x8, [0, 1, 2, 3, 4, 5, 6, 7]);
84
85impl Shr for i64x8 {
86 type Output = Self;
87
88 #[inline]
89 fn shr(self, rhs: Self) -> Self::Output {
90 pick! {
91 if #[cfg(target_feature="avx512f")] {
92 let a: [i64; 8] = cast(self);
96 let r: [i64; 8] = cast(rhs);
97 cast([
98 a[0].wrapping_shr(r[0] as u32),
99 a[1].wrapping_shr(r[1] as u32),
100 a[2].wrapping_shr(r[2] as u32),
101 a[3].wrapping_shr(r[3] as u32),
102 a[4].wrapping_shr(r[4] as u32),
103 a[5].wrapping_shr(r[5] as u32),
104 a[6].wrapping_shr(r[6] as u32),
105 a[7].wrapping_shr(r[7] as u32),
106 ])
107 } else {
108 Self {
110 a: self.a.shr(rhs.a),
111 b: self.b.shr(rhs.b),
112 }
113 }
114 }
115 }
116}
117
118impl Shl for i64x8 {
119 type Output = Self;
120
121 #[inline]
122 fn shl(self, rhs: Self) -> Self::Output {
123 pick! {
124 if #[cfg(target_feature="avx512f")] {
125 let a: [i64; 8] = cast(self);
129 let r: [i64; 8] = cast(rhs);
130 cast([
131 a[0].wrapping_shl(r[0] as u32),
132 a[1].wrapping_shl(r[1] as u32),
133 a[2].wrapping_shl(r[2] as u32),
134 a[3].wrapping_shl(r[3] as u32),
135 a[4].wrapping_shl(r[4] as u32),
136 a[5].wrapping_shl(r[5] as u32),
137 a[6].wrapping_shl(r[6] as u32),
138 a[7].wrapping_shl(r[7] as u32),
139 ])
140 } else {
141 Self {
143 a: self.a.shl(rhs.a),
144 b: self.b.shl(rhs.b),
145 }
146 }
147 }
148 }
149}
150
151impl Add<i64> for i64x8 {
152 type Output = Self;
153 #[inline]
154 fn add(self, rhs: i64) -> Self::Output {
155 self.add(Self::splat(rhs))
156 }
157}
158
159impl Sub<i64> for i64x8 {
160 type Output = Self;
161 #[inline]
162 fn sub(self, rhs: i64) -> Self::Output {
163 self.sub(Self::splat(rhs))
164 }
165}
166
167impl Mul<i64> for i64x8 {
168 type Output = Self;
169 #[inline]
170 fn mul(self, rhs: i64) -> Self::Output {
171 self.mul(Self::splat(rhs))
172 }
173}
174
175impl Add<i64x8> for i64 {
176 type Output = i64x8;
177 #[inline]
178 fn add(self, rhs: i64x8) -> Self::Output {
179 i64x8::splat(self).add(rhs)
180 }
181}
182
183impl Sub<i64x8> for i64 {
184 type Output = i64x8;
185 #[inline]
186 fn sub(self, rhs: i64x8) -> Self::Output {
187 i64x8::splat(self).sub(rhs)
188 }
189}
190
191impl Mul<i64x8> for i64 {
192 type Output = i64x8;
193 #[inline]
194 fn mul(self, rhs: i64x8) -> Self::Output {
195 i64x8::splat(self).mul(rhs)
196 }
197}
198
199impl BitAnd for i64x8 {
200 type Output = Self;
201 #[inline]
202 fn bitand(self, rhs: Self) -> Self::Output {
203 pick! {
204 if #[cfg(target_feature="avx512f")] {
205 Self { avx512: bitand_m512i(self.avx512, rhs.avx512) }
206 } else {
207 Self {
208 a : self.a.bitand(rhs.a),
209 b : self.b.bitand(rhs.b),
210 }
211 }
212 }
213 }
214}
215
216impl BitOr for i64x8 {
217 type Output = Self;
218 #[inline]
219 fn bitor(self, rhs: Self) -> Self::Output {
220 pick! {
221 if #[cfg(target_feature="avx512f")] {
222 Self { avx512: bitor_m512i(self.avx512, rhs.avx512) }
223 } else {
224 Self {
225 a : self.a.bitor(rhs.a),
226 b : self.b.bitor(rhs.b),
227 }
228 }
229 }
230 }
231}
232
233impl BitXor for i64x8 {
234 type Output = Self;
235 #[inline]
236 fn bitxor(self, rhs: Self) -> Self::Output {
237 pick! {
238 if #[cfg(target_feature="avx512f")] {
239 Self { avx512: bitxor_m512i(self.avx512, rhs.avx512) }
240 } else {
241 Self {
242 a : self.a.bitxor(rhs.a),
243 b : self.b.bitxor(rhs.b),
244 }
245 }
246 }
247 }
248}
249
250macro_rules! impl_shl_t_for_i64x8 {
251 ($($shift_type:ty),+ $(,)?) => {
252 $(impl Shl<$shift_type> for i64x8 {
253 type Output = Self;
254 #[inline]
256 fn shl(self, rhs: $shift_type) -> Self::Output {
257 pick! {
258 if #[cfg(target_feature="avx512f")] {
259 let shift = cast(rhs as u64);
260 Self { avx512: shl_all_u64_m512i(self.avx512, shift) }
261 } else {
262 Self {
263 a : self.a.shl(rhs),
264 b : self.b.shl(rhs),
265 }
266 }
267 }
268 }
269 })+
270 };
271}
272impl_shl_t_for_i64x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
273
274macro_rules! impl_shr_t_for_i64x8 {
275 ($($shift_type:ty),+ $(,)?) => {
276 $(impl Shr<$shift_type> for i64x8 {
277 type Output = Self;
278 #[inline]
280 fn shr(self, rhs: $shift_type) -> Self::Output {
281 pick! {
282 if #[cfg(target_feature="avx512f")] {
283 let shift = cast(rhs as u64);
284 Self { avx512: shr_all_i64_m512i(self.avx512, shift) }
285 } else {
286 Self {
287 a : self.a.shr(rhs),
288 b : self.b.shr(rhs),
289 }
290 }
291 }
292 }
293 })+
294 };
295}
296impl_shr_t_for_i64x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
297
298#[expect(deprecated)]
299impl CmpEq for i64x8 {
300 type Output = Self;
301 #[inline]
302 fn simd_eq(self, rhs: Self) -> Self::Output {
303 pick! {
304 if #[cfg(target_feature="avx512f")] {
305 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Eq)}>(self.avx512, rhs.avx512) }
306 } else {
307 Self {
308 a : self.a.simd_eq(rhs.a),
309 b : self.b.simd_eq(rhs.b),
310 }
311 }
312 }
313 }
314}
315
316#[expect(deprecated)]
317impl CmpGt for i64x8 {
318 type Output = Self;
319 #[inline]
320 fn simd_gt(self, rhs: Self) -> Self::Output {
321 pick! {
322 if #[cfg(target_feature="avx512f")] {
323 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Nle)}>(self.avx512, rhs.avx512) }
324 } else {
325 Self {
326 a : self.a.simd_gt(rhs.a),
327 b : self.b.simd_gt(rhs.b),
328 }
329 }
330 }
331 }
332}
333
334#[expect(deprecated)]
335impl CmpLt for i64x8 {
336 type Output = Self;
337 #[inline]
338 fn simd_lt(self, rhs: Self) -> Self::Output {
339 pick! {
340 if #[cfg(target_feature="avx512f")] {
341 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Lt)}>(self.avx512, rhs.avx512) }
342 } else {
343 Self {
344 a : rhs.a.simd_gt(self.a),
345 b : rhs.b.simd_gt(self.b),
346 }
347 }
348 }
349 }
350}
351
352#[expect(deprecated)]
353impl CmpNe for i64x8 {
354 type Output = Self;
355 #[inline]
356 fn simd_ne(self, rhs: Self) -> Self::Output {
357 pick! {
358 if #[cfg(target_feature="avx512f")] {
359 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Ne)}>(self.avx512, rhs.avx512) }
360 } else {
361 Self {
362 a : self.a.simd_ne(rhs.a),
363 b : self.b.simd_ne(rhs.b),
364 }
365 }
366 }
367 }
368}
369
370#[expect(deprecated)]
371impl CmpLe for i64x8 {
372 type Output = Self;
373 #[inline]
374 fn simd_le(self, rhs: Self) -> Self::Output {
375 pick! {
376 if #[cfg(target_feature="avx512f")] {
377 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Le)}>(self.avx512, rhs.avx512) }
378 } else {
379 Self {
380 a : self.a.simd_le(rhs.a),
381 b : self.b.simd_le(rhs.b),
382 }
383 }
384 }
385 }
386}
387
388#[expect(deprecated)]
389impl CmpGe for i64x8 {
390 type Output = Self;
391 #[inline]
392 fn simd_ge(self, rhs: Self) -> Self::Output {
393 pick! {
394 if #[cfg(target_feature="avx512f")] {
395 Self { avx512: cmp_op_mask_i64_m512i::<{cmp_int_op!(Nlt)}>(self.avx512, rhs.avx512) }
396 } else {
397 Self {
398 a : self.a.simd_ge(rhs.a),
399 b : self.b.simd_ge(rhs.b),
400 }
401 }
402 }
403 }
404}
405
406impl i64x8 {
407 #[inline]
408 #[must_use]
409 pub const fn new(array: [i64; 8]) -> Self {
410 unsafe { core::mem::transmute(array) }
411 }
412
413 simd_comparison_fns!();
414
415 #[inline]
416 #[must_use]
417 pub fn blend(self, t: Self, f: Self) -> Self {
418 pick! {
419 if #[cfg(target_feature="avx512f")] {
420 Self { avx512: blend_varying_i8_m512i(f.avx512,t.avx512,movepi8_mask_m512i(self.avx512)) }
421 } else {
422 Self {
423 a : self.a.blend(t.a, f.a),
424 b : self.b.blend(t.b, f.b),
425 }
426 }
427 }
428 }
429
430 #[inline]
433 #[must_use]
434 pub fn is_positive(self) -> Self {
435 pick! {
436 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
437 Self {
439 a: self.a.is_positive(),
440 b: self.b.is_positive(),
441 }
442 } else {
443 self.simd_gt(Self::ZERO)
444 }
445 }
446 }
447
448 #[inline]
451 #[must_use]
452 pub fn is_negative(self) -> Self {
453 pick! {
454 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
455 Self {
457 a: self.a.is_negative(),
458 b: self.b.is_negative(),
459 }
460 } else {
461 self.simd_lt(Self::ZERO)
462 }
463 }
464 }
465
466 #[inline]
467 #[must_use]
468 pub fn reduce_add(self) -> i64 {
469 let array: [i64x4; 2] = cast(self);
470 (array[0] + array[1]).reduce_add()
471 }
472
473 #[inline]
474 #[must_use]
475 pub fn reduce_max(self) -> i64 {
476 let array: [i64x4; 2] = cast(self);
477 array[0].max(array[1]).reduce_max()
478 }
479
480 #[inline]
481 #[must_use]
482 pub fn reduce_min(self) -> i64 {
483 let array: [i64x4; 2] = cast(self);
484 array[0].min(array[1]).reduce_min()
485 }
486
487 #[inline]
488 #[must_use]
489 pub fn abs(self) -> Self {
490 pick! {
491 if #[cfg(target_feature="avx512f")] {
492 let arr: [i64; 8] = cast(self);
494 cast(
495 [
496 arr[0].wrapping_abs(),
497 arr[1].wrapping_abs(),
498 arr[2].wrapping_abs(),
499 arr[3].wrapping_abs(),
500 arr[4].wrapping_abs(),
501 arr[5].wrapping_abs(),
502 arr[6].wrapping_abs(),
503 arr[7].wrapping_abs(),
504 ])
505 } else {
506 Self {
507 a : self.a.abs(),
508 b : self.b.abs(),
509 }
510 }
511 }
512 }
513
514 #[inline]
515 #[must_use]
516 pub fn unsigned_abs(self) -> u64x8 {
517 pick! {
518 if #[cfg(target_feature="avx512f")] {
519 let arr: [i64; 8] = cast(self);
521 cast(
522 [
523 arr[0].unsigned_abs(),
524 arr[1].unsigned_abs(),
525 arr[2].unsigned_abs(),
526 arr[3].unsigned_abs(),
527 arr[4].unsigned_abs(),
528 arr[5].unsigned_abs(),
529 arr[6].unsigned_abs(),
530 arr[7].unsigned_abs(),
531 ])
532 } else {
533 u64x8 {
534 a : self.a.unsigned_abs(),
535 b : self.b.unsigned_abs(),
536 }
537 }
538 }
539 }
540
541 signed_fn_signum!();
542
543 #[inline]
544 #[must_use]
545 pub fn round_float(self) -> f64x8 {
546 let arr: [i64; 8] = cast(self);
547 cast([
548 arr[0] as f64,
549 arr[1] as f64,
550 arr[2] as f64,
551 arr[3] as f64,
552 arr[4] as f64,
553 arr[5] as f64,
554 arr[6] as f64,
555 arr[7] as f64,
556 ])
557 }
558
559 #[inline]
562 #[must_use]
563 #[doc(alias("movemask", "move_mask"))]
564 pub fn to_bitmask(self) -> u32 {
565 pick! {
566 if #[cfg(target_feature="avx512dq")] {
567 movepi64_mask_m512d(cast(self.avx512)) as u32
569 } else {
570 self.a.to_bitmask() | (self.b.to_bitmask() << 4)
571 }
572 }
573 }
574
575 #[inline]
577 #[must_use]
578 pub fn any(self) -> bool {
579 pick! {
580 if #[cfg(target_feature="avx512f")] {
581 movepi64_mask_m512d(cast(self.avx512)) != 0
582 } else {
583 let [a, b]: [i64x4; 2] = cast(self);
584 (a | b).any()
585 }
586 }
587 }
588
589 #[inline]
591 #[must_use]
592 pub fn all(self) -> bool {
593 pick! {
594 if #[cfg(target_feature="avx512bw")] {
595 movepi64_mask_m512d(cast(self.avx512)) == 0b11111111
596 } else {
597 let [a, b]: [i64x4; 2] = cast(self);
598 (a & b).all()
599 }
600 }
601 }
602
603 #[inline]
605 #[must_use]
606 pub fn none(self) -> bool {
607 !self.any()
608 }
609
610 #[must_use]
612 #[inline]
613 pub fn transpose(data: [i64x8; 8]) -> [i64x8; 8] {
614 #[inline(always)]
617 fn transpose_column(data: &[i64x8; 8], index: usize) -> i64x8 {
618 i64x8::new([
619 data[0].as_array()[index],
620 data[1].as_array()[index],
621 data[2].as_array()[index],
622 data[3].as_array()[index],
623 data[4].as_array()[index],
624 data[5].as_array()[index],
625 data[6].as_array()[index],
626 data[7].as_array()[index],
627 ])
628 }
629
630 [
631 transpose_column(&data, 0),
632 transpose_column(&data, 1),
633 transpose_column(&data, 2),
634 transpose_column(&data, 3),
635 transpose_column(&data, 4),
636 transpose_column(&data, 5),
637 transpose_column(&data, 6),
638 transpose_column(&data, 7),
639 ]
640 }
641
642 #[inline]
643 pub fn to_array(self) -> [i64; 8] {
644 cast(self)
645 }
646
647 #[inline]
648 pub fn as_array(&self) -> &[i64; 8] {
649 cast_ref(self)
650 }
651
652 #[inline]
653 pub fn as_mut_array(&mut self) -> &mut [i64; 8] {
654 cast_mut(self)
655 }
656
657 #[inline]
658 #[must_use]
659 pub fn min(self, rhs: Self) -> Self {
660 pick! {
661 if #[cfg(target_feature="avx512f")] {
662 Self { avx512: min_i64_m512i(self.avx512, rhs.avx512) }
663 } else {
664 Self {
665 a: self.a.min(rhs.a),
666 b: self.b.min(rhs.b),
667 }
668 }
669 }
670 }
671
672 #[inline]
673 #[must_use]
674 pub fn max(self, rhs: Self) -> Self {
675 pick! {
676 if #[cfg(target_feature="avx512f")] {
677 Self { avx512: max_i64_m512i(self.avx512, rhs.avx512) }
678 } else {
679 Self {
680 a: self.a.max(rhs.a),
681 b: self.b.max(rhs.b),
682 }
683 }
684 }
685 }
686
687 integer_fn_clamp!();
688
689 #[inline]
690 #[must_use]
691 pub fn saturating_add(self, rhs: Self) -> Self {
692 pick! {
693 if #[cfg(target_feature="avx512f")] {
694 let result = self + rhs;
695 let overflow = (!(self ^ rhs) & (self ^ result)).is_negative();
696 let negative = self.is_negative();
697
698 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
699 } else {
700 Self {
701 a: self.a.saturating_add(rhs.a),
702 b: self.b.saturating_add(rhs.b),
703 }
704 }
705 }
706 }
707
708 #[inline]
709 #[must_use]
710 pub fn saturating_sub(self, rhs: Self) -> Self {
711 pick! {
712 if #[cfg(target_feature="avx512f")] {
713 let result = self - rhs;
714 let overflow = ((self ^ rhs) & (self ^ result)).is_negative();
715 let negative = self.is_negative();
716
717 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
718 } else {
719 Self {
720 a: self.a.saturating_sub(rhs.a),
721 b: self.b.saturating_sub(rhs.b),
722 }
723 }
724 }
725 }
726
727 #[inline]
729 #[must_use]
730 pub fn saturating_mul(self, rhs: Self) -> Self {
731 let self_array = self.to_array();
732 let rhs_array = rhs.to_array();
733
734 Self::new([
735 self_array[0].saturating_mul(rhs_array[0]),
736 self_array[1].saturating_mul(rhs_array[1]),
737 self_array[2].saturating_mul(rhs_array[2]),
738 self_array[3].saturating_mul(rhs_array[3]),
739 self_array[4].saturating_mul(rhs_array[4]),
740 self_array[5].saturating_mul(rhs_array[5]),
741 self_array[6].saturating_mul(rhs_array[6]),
742 self_array[7].saturating_mul(rhs_array[7]),
743 ])
744 }
745
746 integer_fn_saturating_div!([0, 1, 2, 3, 4, 5, 6, 7]);
747}
748
749impl Not for i64x8 {
750 type Output = Self;
751 #[inline]
752 fn not(self) -> Self::Output {
753 pick! {
754 if #[cfg(target_feature="avx512f")] {
755 Self { avx512: bitxor_m512i(self.avx512, set_splat_i64_m512i(-1)) }
756 } else {
757 Self {
758 a : self.a.not(),
759 b : self.b.not(),
760 }
761 }
762 }
763 }
764}