Skip to main content

wide/
u64x8_.rs

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      /// Shifts all lanes by the value given.
189      #[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      /// Shifts all lanes by the value given.
213      #[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  /// Transpose matrix of 8x8 `u64` matrix. Currently not accelerated.
447  #[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  /// Lanewise saturating multiply.
533  #[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}