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 i64x2 { 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 i64x2 { pub(crate) simd: v128 }
14
15 impl Default for i64x2 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for i64x2 {
22 fn eq(&self, other: &Self) -> bool {
23 u64x2_all_true(i64x2_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for i64x2 { }
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 i64x2 { pub(crate) neon : int64x2_t }
33
34 impl Default for i64x2 {
35 #[inline]
36 fn default() -> Self {
37 unsafe { Self { neon: vdupq_n_s64(0)} }
38 }
39 }
40
41 impl PartialEq for i64x2 {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 unsafe {
45 vgetq_lane_s64(self.neon,0) == vgetq_lane_s64(other.neon,0) && vgetq_lane_s64(self.neon,1) == vgetq_lane_s64(other.neon,1)
46 }
47 }
48 }
49
50 impl Eq for i64x2 { }
51 } else {
52 #[derive(Default, Clone, Copy, PartialEq, Eq)]
53 #[repr(C, align(16))]
54 pub struct i64x2 { arr: [i64;2] }
55 }
56}
57
58int_uint_consts!(i64, 2, i64x2, 128);
59
60unsafe impl Zeroable for i64x2 {}
61unsafe impl Pod for i64x2 {}
62
63impl AlignTo for i64x2 {
64 type Elem = i64;
65}
66
67impl Add for i64x2 {
68 type Output = Self;
69 #[inline]
70 fn add(self, rhs: Self) -> Self::Output {
71 pick! {
72 if #[cfg(target_feature="sse2")] {
73 Self { sse: add_i64_m128i(self.sse, rhs.sse) }
74 } else if #[cfg(target_feature="simd128")] {
75 Self { simd: i64x2_add(self.simd, rhs.simd) }
76 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
77 unsafe { Self { neon: vaddq_s64(self.neon, rhs.neon) } }
78 } else {
79 Self { arr: [
80 self.arr[0].wrapping_add(rhs.arr[0]),
81 self.arr[1].wrapping_add(rhs.arr[1]),
82 ]}
83 }
84 }
85 }
86}
87
88impl Sub for i64x2 {
89 type Output = Self;
90 #[inline]
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: i64x2_sub(self.simd, rhs.simd) }
97 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
98 unsafe { Self { neon: vsubq_s64(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 i64x2 {
111 type Output = Self;
112 #[inline]
113 fn mul(self, rhs: Self) -> Self::Output {
114 pick! {
115 if #[cfg(target_feature="simd128")] {
116 Self { simd: i64x2_mul(self.simd, rhs.simd) }
117 } else {
118 let arr1: [i64; 2] = cast(self);
119 let arr2: [i64; 2] = cast(rhs);
120 cast([
121 arr1[0].wrapping_mul(arr2[0]),
122 arr1[1].wrapping_mul(arr2[1]),
123 ])
124 }
125 }
126 }
127}
128
129integer_impl_div_rem!(i64, i64x2, [0, 1]);
130
131impl Add<i64> for i64x2 {
132 type Output = Self;
133 #[inline]
134 fn add(self, rhs: i64) -> Self::Output {
135 self.add(Self::splat(rhs))
136 }
137}
138
139impl Sub<i64> for i64x2 {
140 type Output = Self;
141 #[inline]
142 fn sub(self, rhs: i64) -> Self::Output {
143 self.sub(Self::splat(rhs))
144 }
145}
146
147impl Mul<i64> for i64x2 {
148 type Output = Self;
149 #[inline]
150 fn mul(self, rhs: i64) -> Self::Output {
151 self.mul(Self::splat(rhs))
152 }
153}
154
155impl Add<i64x2> for i64 {
156 type Output = i64x2;
157 #[inline]
158 fn add(self, rhs: i64x2) -> Self::Output {
159 i64x2::splat(self).add(rhs)
160 }
161}
162
163impl Sub<i64x2> for i64 {
164 type Output = i64x2;
165 #[inline]
166 fn sub(self, rhs: i64x2) -> Self::Output {
167 i64x2::splat(self).sub(rhs)
168 }
169}
170
171impl Mul<i64x2> for i64 {
172 type Output = i64x2;
173 #[inline]
174 fn mul(self, rhs: i64x2) -> Self::Output {
175 i64x2::splat(self).mul(rhs)
176 }
177}
178
179impl BitAnd for i64x2 {
180 type Output = Self;
181 #[inline]
182 fn bitand(self, rhs: Self) -> Self::Output {
183 pick! {
184 if #[cfg(target_feature="sse2")] {
185 Self { sse: bitand_m128i(self.sse, rhs.sse) }
186 } else if #[cfg(target_feature="simd128")] {
187 Self { simd: v128_and(self.simd, rhs.simd) }
188 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
189 unsafe {Self { neon: vandq_s64(self.neon, rhs.neon) }}
190 } else {
191 Self { arr: [
192 self.arr[0].bitand(rhs.arr[0]),
193 self.arr[1].bitand(rhs.arr[1]),
194 ]}
195 }
196 }
197 }
198}
199
200impl BitOr for i64x2 {
201 type Output = Self;
202 #[inline]
203 fn bitor(self, rhs: Self) -> Self::Output {
204 pick! {
205 if #[cfg(target_feature="sse2")] {
206 Self { sse: bitor_m128i(self.sse, rhs.sse) }
207 } else if #[cfg(target_feature="simd128")] {
208 Self { simd: v128_or(self.simd, rhs.simd) }
209 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
210 unsafe {Self { neon: vorrq_s64(self.neon, rhs.neon) }}
211 } else {
212 Self { arr: [
213 self.arr[0].bitor(rhs.arr[0]),
214 self.arr[1].bitor(rhs.arr[1]),
215 ]}
216 }
217 }
218 }
219}
220
221impl BitXor for i64x2 {
222 type Output = Self;
223 #[inline]
224 fn bitxor(self, rhs: Self) -> Self::Output {
225 pick! {
226 if #[cfg(target_feature="sse2")] {
227 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
228 } else if #[cfg(target_feature="simd128")] {
229 Self { simd: v128_xor(self.simd, rhs.simd) }
230 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
231 unsafe {Self { neon: veorq_s64(self.neon, rhs.neon) }}
232 } else {
233 Self { arr: [
234 self.arr[0].bitxor(rhs.arr[0]),
235 self.arr[1].bitxor(rhs.arr[1]),
236 ]}
237 }
238 }
239 }
240}
241
242impl Shl for i64x2 {
248 type Output = Self;
249
250 #[inline]
251 fn shl(self, rhs: Self) -> Self::Output {
252 pick! {
253 if #[cfg(target_feature="avx2")] {
254 let shift_by = rhs & Self::splat(63);
256 Self { sse: shl_each_u64_m128i(self.sse, shift_by.sse) }
257 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
258 unsafe {
259 let shift_by = vandq_s64(rhs.neon, vmovq_n_s64(63));
261 Self { neon: vshlq_s64(self.neon, shift_by) }
262 }
263 } else {
264 let arr: [i64; 2] = cast(self);
265 let rhs: [i64; 2] = cast(rhs);
266 cast([
267 arr[0].wrapping_shl(rhs[0] as u32),
268 arr[1].wrapping_shl(rhs[1] as u32),
269 ])
270 }
271 }
272 }
273}
274
275macro_rules! impl_shl_t_for_i64x2 {
276 ($($shift_type:ty),+ $(,)?) => {
277 $(impl Shl<$shift_type> for i64x2 {
278 type Output = Self;
279 #[inline]
281 fn shl(self, rhs: $shift_type) -> Self::Output {
282 pick! {
283 if #[cfg(target_feature="sse2")] {
284 let shift = cast([rhs as u64, 0]);
285 Self { sse: shl_all_u64_m128i(self.sse, shift) }
286 } else if #[cfg(target_feature="simd128")] {
287 Self { simd: i64x2_shl(self.simd, rhs as u32) }
288 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
289 unsafe {Self { neon: vshlq_s64(self.neon, vmovq_n_s64(rhs as i64)) }}
290 } else {
291 let u = rhs as u32;
292 Self { arr: [
293 self.arr[0].wrapping_shl(u),
294 self.arr[1].wrapping_shl(u),
295 ]}
296 }
297 }
298 }
299 })+
300 };
301}
302impl_shl_t_for_i64x2!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
303
304impl Shr for i64x2 {
310 type Output = Self;
311
312 #[inline]
313 fn shr(self, rhs: Self) -> Self::Output {
314 pick! {
315 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
316 unsafe {
317 let shift_by = vnegq_s64(vandq_s64(rhs.neon, vmovq_n_s64(63)));
320 Self { neon: vshlq_s64(self.neon, shift_by) }
321 }
322 } else {
323 let arr: [i64; 2] = cast(self);
324 let rhs: [i64; 2] = cast(rhs);
325 cast([
326 arr[0].wrapping_shr(rhs[0] as u32),
327 arr[1].wrapping_shr(rhs[1] as u32),
328 ])
329 }
330 }
331 }
332}
333
334macro_rules! impl_shr_t_for_i64x2 {
335 ($($shift_type:ty),+ $(,)?) => {
336 $(impl Shr<$shift_type> for i64x2 {
337 type Output = Self;
338 #[inline]
340 fn shr(self, rhs: $shift_type) -> Self::Output {
341 pick! {
342 if #[cfg(target_feature="simd128")] {
343 Self { simd: i64x2_shr(self.simd, rhs as u32) }
344 } else {
345 let u = rhs as u32;
346 let arr: [i64; 2] = cast(self);
347 cast([
348 arr[0].wrapping_shr(u),
349 arr[1].wrapping_shr(u),
350 ])
351 }
352 }
353 }
354 })+
355 };
356}
357
358impl_shr_t_for_i64x2!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
359
360#[expect(deprecated)]
361impl CmpEq for i64x2 {
362 type Output = Self;
363 #[inline]
364 fn simd_eq(self, rhs: Self) -> Self::Output {
365 pick! {
366 if #[cfg(target_feature="sse4.1")] {
367 Self { sse: cmp_eq_mask_i64_m128i(self.sse, rhs.sse) }
368 } else if #[cfg(target_feature="simd128")] {
369 Self { simd: i64x2_eq(self.simd, rhs.simd) }
370 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
371 unsafe {Self { neon: vreinterpretq_s64_u64(vceqq_s64(self.neon, rhs.neon)) }}
372 } else {
373 let s: [i64;2] = cast(self);
374 let r: [i64;2] = cast(rhs);
375 cast([
376 if s[0] == r[0] { -1_i64 } else { 0 },
377 if s[1] == r[1] { -1_i64 } else { 0 },
378 ])
379 }
380 }
381 }
382}
383
384#[expect(deprecated)]
385impl CmpGt for i64x2 {
386 type Output = Self;
387 #[inline]
388 fn simd_gt(self, rhs: Self) -> Self::Output {
389 pick! {
390 if #[cfg(target_feature="sse4.2")] {
391 Self { sse: cmp_gt_mask_i64_m128i(self.sse, rhs.sse) }
392 } else if #[cfg(target_feature="simd128")] {
393 Self { simd: i64x2_gt(self.simd, rhs.simd) }
394 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
395 unsafe {Self { neon: vreinterpretq_s64_u64(vcgtq_s64(self.neon, rhs.neon)) }}
396 } else {
397 let s: [i64;2] = cast(self);
398 let r: [i64;2] = cast(rhs);
399 cast([
400 if s[0] > r[0] { -1_i64 } else { 0 },
401 if s[1] > r[1] { -1_i64 } else { 0 },
402 ])
403 }
404 }
405 }
406}
407
408#[expect(deprecated)]
409impl CmpLt for i64x2 {
410 type Output = Self;
411 #[inline]
412 fn simd_lt(self, rhs: Self) -> Self::Output {
413 pick! {
414 if #[cfg(target_feature="sse4.2")] {
415 Self { sse: cmp_gt_mask_i64_m128i( rhs.sse, self.sse) }
417 } else if #[cfg(target_feature="simd128")] {
418 Self { simd: i64x2_lt(self.simd, rhs.simd) }
419 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
420 unsafe {Self { neon: vreinterpretq_s64_u64(vcltq_s64(self.neon, rhs.neon)) }}
421 } else {
422 let s: [i64;2] = cast(self);
423 let r: [i64;2] = cast(rhs);
424 cast([
425 if s[0] < r[0] { -1_i64 } else { 0 },
426 if s[1] < r[1] { -1_i64 } else { 0 },
427 ])
428 }
429 }
430 }
431}
432
433#[expect(deprecated)]
434impl CmpNe for i64x2 {
435 type Output = Self;
436 #[inline]
437 fn simd_ne(self, rhs: Self) -> Self::Output {
438 pick! {
439 if #[cfg(target_feature="sse4.1")] {
440 !self.simd_eq(rhs)
441 } else if #[cfg(target_feature="simd128")] {
442 Self { simd: i64x2_ne(self.simd, rhs.simd) }
443 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
444 !self.simd_eq(rhs)
445 } else {
446 let s: [i64;2] = cast(self);
447 let r: [i64;2] = cast(rhs);
448 cast([
449 if s[0] != r[0] { -1_i64 } else { 0 },
450 if s[1] != r[1] { -1_i64 } else { 0 },
451 ])
452 }
453 }
454 }
455}
456
457#[expect(deprecated)]
458impl CmpLe for i64x2 {
459 type Output = Self;
460 #[inline]
461 fn simd_le(self, rhs: Self) -> Self::Output {
462 pick! {
463 if #[cfg(target_feature="sse4.1")] {
464 !self.simd_gt(rhs)
465 } else if #[cfg(target_feature="simd128")] {
466 Self { simd: i64x2_le(self.simd, rhs.simd) }
467 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
468 !self.simd_gt(rhs)
469 } else {
470 let s: [i64;2] = cast(self);
471 let r: [i64;2] = cast(rhs);
472 cast([
473 if s[0] <= r[0] { -1_i64 } else { 0 },
474 if s[1] <= r[1] { -1_i64 } else { 0 },
475 ])
476 }
477 }
478 }
479}
480
481#[expect(deprecated)]
482impl CmpGe for i64x2 {
483 type Output = Self;
484 #[inline]
485 fn simd_ge(self, rhs: Self) -> Self::Output {
486 pick! {
487 if #[cfg(target_feature="sse4.1")] {
488 !self.simd_lt(rhs)
489 } else if #[cfg(target_feature="simd128")] {
490 Self { simd: i64x2_ge(self.simd, rhs.simd) }
491 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
492 !self.simd_lt(rhs)
493 } else {
494 let s: [i64;2] = cast(self);
495 let r: [i64;2] = cast(rhs);
496 cast([
497 if s[0] >= r[0] { -1_i64 } else { 0 },
498 if s[1] >= r[1] { -1_i64 } else { 0 },
499 ])
500 }
501 }
502 }
503}
504
505impl i64x2 {
506 #[inline]
507 #[must_use]
508 pub const fn new(array: [i64; 2]) -> Self {
509 unsafe { core::mem::transmute(array) }
510 }
511
512 simd_comparison_fns!();
513
514 #[inline]
515 #[must_use]
516 pub fn blend(self, t: Self, f: Self) -> Self {
517 pick! {
518 if #[cfg(target_feature="sse4.1")] {
519 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
520 } else if #[cfg(target_feature="simd128")] {
521 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
522 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
523 unsafe {Self { neon: vbslq_s64(vreinterpretq_u64_s64(self.neon), t.neon, f.neon) }}
524 } else {
525 generic_bit_blend(self, t, f)
526 }
527 }
528 }
529
530 #[inline]
533 #[must_use]
534 pub fn is_positive(self) -> Self {
535 pick! {
536 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
537 Self { neon: unsafe { vreinterpretq_s64_u64(vcgtzq_s64(self.neon)) } }
538 } else {
539 self.simd_gt(Self::ZERO)
540 }
541 }
542 }
543
544 #[inline]
547 #[must_use]
548 pub fn is_negative(self) -> Self {
549 pick! {
550 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
551 Self { neon: unsafe { vreinterpretq_s64_u64(vcltzq_s64(self.neon)) } }
552 } else {
553 self.simd_lt(Self::ZERO)
554 }
555 }
556 }
557
558 #[inline]
559 #[must_use]
560 pub fn reduce_add(self) -> i64 {
561 pick! {
562 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
563 let array: [i64; 2] = cast(self);
564 array[0].wrapping_add(array[1])
565 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
566 unsafe { vgetq_lane_s64(self.neon, 0).wrapping_add(vgetq_lane_s64(self.neon, 1)) }
567 } else {
568 self.arr[0].wrapping_add(self.arr[1])
569 }
570 }
571 }
572
573 #[inline]
574 #[must_use]
575 pub fn reduce_max(self) -> i64 {
576 pick! {
577 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
578 let array: [i64; 2] = cast(self);
579 array[0].max(array[1])
580 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
581 unsafe { vgetq_lane_s64(self.neon, 0).max(vgetq_lane_s64(self.neon, 1)) }
582 } else {
583 self.arr[0].max(self.arr[1])
584 }
585 }
586 }
587
588 #[inline]
589 #[must_use]
590 pub fn reduce_min(self) -> i64 {
591 pick! {
592 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
593 let array: [i64; 2] = cast(self);
594 array[0].min(array[1])
595 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
596 unsafe { vgetq_lane_s64(self.neon, 0).min(vgetq_lane_s64(self.neon, 1)) }
597 } else {
598 self.arr[0].min(self.arr[1])
599 }
600 }
601 }
602
603 #[inline]
604 #[must_use]
605 pub fn abs(self) -> Self {
606 pick! {
607 if #[cfg(target_feature="simd128")] {
609 Self { simd: i64x2_abs(self.simd) }
610 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
611 unsafe {Self { neon: vabsq_s64(self.neon) }}
612 } else {
613 let arr: [i64; 2] = cast(self);
614 cast(
615 [
616 arr[0].wrapping_abs(),
617 arr[1].wrapping_abs(),
618 ])
619 }
620 }
621 }
622
623 #[inline]
624 #[must_use]
625 pub fn unsigned_abs(self) -> u64x2 {
626 pick! {
627 if #[cfg(target_feature="simd128")] {
629 u64x2 { simd: i64x2_abs(self.simd) }
630 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
631 unsafe {u64x2 { neon: vreinterpretq_u64_s64(vabsq_s64(self.neon)) }}
632 } else {
633 let arr: [i64; 2] = cast(self);
634 cast(
635 [
636 arr[0].unsigned_abs(),
637 arr[1].unsigned_abs(),
638 ])
639 }
640 }
641 }
642
643 signed_fn_signum!();
644
645 #[inline]
646 #[must_use]
647 pub fn round_float(self) -> f64x2 {
648 let arr: [i64; 2] = cast(self);
649 cast([arr[0] as f64, arr[1] as f64])
650 }
651
652 #[inline]
655 #[must_use]
656 #[doc(alias("movemask", "move_mask"))]
657 pub fn to_bitmask(self) -> u32 {
658 pick! {
659 if #[cfg(target_feature="sse")] {
660 move_mask_m128d(cast(self.sse)) as u32
662 } else if #[cfg(target_feature="simd128")] {
663 i64x2_bitmask(self.simd) as u32
664 } else {
665 let arr: [u64; 2] = cast(self);
667 (arr[0] >> 63 | ((arr[1] >> 62) & 2)) as u32
668 }
669 }
670 }
671
672 #[inline]
674 #[must_use]
675 pub fn any(self) -> bool {
676 pick! {
677 if #[cfg(target_feature="sse")] {
678 move_mask_m128d(cast(self.sse)) != 0
680 } else if #[cfg(target_feature="simd128")] {
681 i64x2_bitmask(self.simd) != 0
682 } else {
683 let v : [u64;2] = cast(self);
684 ((v[0] | v[1]) & 0x8000000000000000) != 0
685 }
686 }
687 }
688
689 #[inline]
691 #[must_use]
692 pub fn all(self) -> bool {
693 pick! {
694 if #[cfg(target_feature="avx2")] {
695 move_mask_m128d(cast(self.sse)) == 0b11
697 } else if #[cfg(target_feature="simd128")] {
698 i64x2_bitmask(self.simd) == 0b11
699 } else {
700 let v : [u64;2] = cast(self);
701 ((v[0] & v[1]) & 0x8000000000000000) == 0x8000000000000000
702 }
703 }
704 }
705
706 #[inline]
708 #[must_use]
709 pub fn none(self) -> bool {
710 !self.any()
711 }
712
713 #[must_use]
715 #[inline]
716 #[allow(dead_code)]
717 pub(crate) fn unpack_lo(self, b: Self) -> Self {
718 pick! {
719 if #[cfg(target_feature="sse2")] {
720 Self { sse: unpack_low_i64_m128i(self.sse, b.sse) }
721 } else if #[cfg(target_feature="simd128")] {
722 Self { simd: i64x2_shuffle::<0, 2>(self.simd, b.simd) }
723 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
724 Self { neon: unsafe { vzip1q_s64(self.neon, b.neon) } }
725 } else {
726 Self::new([self.as_array()[0], b.as_array()[0]])
727 }
728 }
729 }
730
731 #[must_use]
733 #[inline]
734 #[allow(dead_code)]
735 pub(crate) fn unpack_hi(self, b: Self) -> Self {
736 pick! {
737 if #[cfg(target_feature="sse2")] {
738 Self { sse: unpack_high_i64_m128i(self.sse, b.sse) }
739 } else if #[cfg(target_feature="simd128")] {
740 Self { simd: i64x2_shuffle::<1, 3>(self.simd, b.simd) }
741 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
742 Self { neon: unsafe { vzip2q_s64(self.neon, b.neon) } }
743 } else {
744 Self::new([self.as_array()[1], b.as_array()[1]])
745 }
746 }
747 }
748
749 #[inline]
751 pub fn transpose(data: [i64x2; 2]) -> [i64x2; 2] {
752 pick! {
753 if #[cfg(any(
754 target_feature="sse2",
755 all(target_feature="neon",target_arch="aarch64"),
756 target_feature="simd128",
757 ))] {
758 [data[0].unpack_lo(data[1]), data[0].unpack_hi(data[1])]
759 } else {
760 let [x, y, z, w]: [i64; 4] = cast(data);
761 cast([x, z, y, w])
762 }
763 }
764 }
765
766 #[inline]
767 pub fn to_array(self) -> [i64; 2] {
768 cast(self)
769 }
770
771 #[inline]
772 pub fn as_array(&self) -> &[i64; 2] {
773 cast_ref(self)
774 }
775
776 #[inline]
777 pub fn as_mut_array(&mut self) -> &mut [i64; 2] {
778 cast_mut(self)
779 }
780
781 #[inline]
782 #[must_use]
783 pub fn min(self, rhs: Self) -> Self {
784 self.simd_lt(rhs).blend(self, rhs)
785 }
786
787 #[inline]
788 #[must_use]
789 pub fn max(self, rhs: Self) -> Self {
790 self.simd_gt(rhs).blend(self, rhs)
791 }
792
793 integer_fn_clamp!();
794
795 #[inline]
796 #[must_use]
797 pub fn saturating_add(self, rhs: Self) -> Self {
798 pick! {
799 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
800 let result = self + rhs;
801 let overflow = (!(self ^ rhs) & (self ^ result)).is_negative();
802 let negative = self.is_negative();
803
804 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
805 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
806 unsafe { Self { neon: vqaddq_s64(self.neon, rhs.neon) } }
807 } else {
808 Self {
809 arr: [
810 self.arr[0].saturating_add(rhs.arr[0]),
811 self.arr[1].saturating_add(rhs.arr[1]),
812 ],
813 }
814 }
815 }
816 }
817
818 #[inline]
819 #[must_use]
820 pub fn saturating_sub(self, rhs: Self) -> Self {
821 pick! {
822 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
823 let result = self - rhs;
824 let overflow = ((self ^ rhs) & (self ^ result)).is_negative();
825 let negative = self.is_negative();
826
827 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
828 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
829 unsafe { Self { neon: vqsubq_s64(self.neon, rhs.neon) } }
830 } else {
831 Self {
832 arr: [
833 self.arr[0].saturating_sub(rhs.arr[0]),
834 self.arr[1].saturating_sub(rhs.arr[1]),
835 ],
836 }
837 }
838 }
839 }
840
841 #[inline]
843 #[must_use]
844 pub fn saturating_mul(self, rhs: Self) -> Self {
845 let self_array = self.to_array();
846 let rhs_array = rhs.to_array();
847
848 Self::new([
849 self_array[0].saturating_mul(rhs_array[0]),
850 self_array[1].saturating_mul(rhs_array[1]),
851 ])
852 }
853
854 integer_fn_saturating_div!([0, 1]);
855}