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 u32x16 { pub(crate) avx512: m512i }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq, Eq)]
10 #[repr(C, align(64))]
11 pub struct u32x16 { pub(crate) a : u32x8, pub(crate) b : u32x8 }
12 }
13}
14
15int_uint_consts!(u32, 16, u32x16, 512);
16
17unsafe impl Zeroable for u32x16 {}
18unsafe impl Pod for u32x16 {}
19
20impl AlignTo for u32x16 {
21 type Elem = u32;
22}
23
24impl Add for u32x16 {
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_i32_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 u32x16 {
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_i32_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 Add<u32> for u32x16 {
59 type Output = Self;
60 #[inline]
61 fn add(self, rhs: u32) -> Self::Output {
62 self.add(Self::splat(rhs))
63 }
64}
65
66impl Sub<u32> for u32x16 {
67 type Output = Self;
68 #[inline]
69 fn sub(self, rhs: u32) -> Self::Output {
70 self.sub(Self::splat(rhs))
71 }
72}
73
74impl Mul<u32> for u32x16 {
75 type Output = Self;
76 #[inline]
77 fn mul(self, rhs: u32) -> Self::Output {
78 self * Self::splat(rhs)
79 }
80}
81
82impl Add<u32x16> for u32 {
83 type Output = u32x16;
84 #[inline]
85 fn add(self, rhs: u32x16) -> Self::Output {
86 u32x16::splat(self).add(rhs)
87 }
88}
89
90impl Sub<u32x16> for u32 {
91 type Output = u32x16;
92 #[inline]
93 fn sub(self, rhs: u32x16) -> Self::Output {
94 u32x16::splat(self).sub(rhs)
95 }
96}
97
98impl Mul<u32x16> for u32 {
99 type Output = u32x16;
100
101 #[inline]
102 fn mul(self, rhs: u32x16) -> Self::Output {
103 u32x16::splat(self) * rhs
104 }
105}
106
107impl Mul for u32x16 {
108 type Output = Self;
109 #[inline]
110 fn mul(self, rhs: Self) -> Self::Output {
111 pick! {
112 if #[cfg(target_feature="avx512f")] {
113 Self { avx512: mul_i32_keep_low_m512i(self.avx512, rhs.avx512) }
114 } else {
115 Self {
116 a : self.a.mul(rhs.a),
117 b : self.b.mul(rhs.b),
118 }
119 }
120 }
121 }
122}
123
124integer_impl_div_rem!(
125 u32,
126 u32x16,
127 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
128);
129
130impl BitAnd for u32x16 {
131 type Output = Self;
132 #[inline]
133 fn bitand(self, rhs: Self) -> Self::Output {
134 pick! {
135 if #[cfg(target_feature="avx512f")] {
136 Self { avx512: bitand_m512i(self.avx512, rhs.avx512) }
137 } else {
138 Self {
139 a : self.a.bitand(rhs.a),
140 b : self.b.bitand(rhs.b),
141 }
142 }
143 }
144 }
145}
146
147impl BitOr for u32x16 {
148 type Output = Self;
149 #[inline]
150 fn bitor(self, rhs: Self) -> Self::Output {
151 pick! {
152 if #[cfg(target_feature="avx512f")] {
153 Self { avx512: bitor_m512i(self.avx512, rhs.avx512) }
154 } else {
155 Self {
156 a : self.a.bitor(rhs.a),
157 b : self.b.bitor(rhs.b),
158 }
159 }
160 }
161 }
162}
163
164impl BitXor for u32x16 {
165 type Output = Self;
166 #[inline]
167 fn bitxor(self, rhs: Self) -> Self::Output {
168 pick! {
169 if #[cfg(target_feature="avx512f")] {
170 Self { avx512: bitxor_m512i(self.avx512, rhs.avx512) }
171 } else {
172 Self {
173 a : self.a.bitxor(rhs.a),
174 b : self.b.bitxor(rhs.b),
175 }
176 }
177 }
178 }
179}
180
181impl From<u16x16> for u32x16 {
182 #[inline]
184 fn from(v: u16x16) -> Self {
185 pick! {
186 if #[cfg(target_feature = "avx512f")] {
187 Self {
188 avx512: convert_to_u32_m512i_from_u16_m256i(v.avx2)
189 }
190 } else if #[cfg(target_feature = "avx2")] {
191 let lo: m128i = extract_m128i_from_m256i::<0>(v.avx2);
192 let hi: m128i = extract_m128i_from_m256i::<1>(v.avx2);
193 Self {
194 a: u32x8 { avx2: convert_to_i32_m256i_from_u16_m128i(lo) },
195 b: u32x8 { avx2: convert_to_i32_m256i_from_u16_m128i(hi) },
196 }
197 } else if #[cfg(target_feature = "sse2")] {
198 Self {
199 a: u32x8 {
200 a: u32x4 {
201 sse: shr_imm_u32_m128i::<16>(unpack_low_i16_m128i(v.a.sse, v.a.sse))
202 },
203 b: u32x4 {
204 sse: shr_imm_u32_m128i::<16>(unpack_high_i16_m128i(v.a.sse, v.a.sse))
205 },
206 },
207 b: u32x8 {
208 a: u32x4 {
209 sse: shr_imm_u32_m128i::<16>(unpack_low_i16_m128i(v.b.sse, v.b.sse))
210 },
211 b: u32x4 {
212 sse: shr_imm_u32_m128i::<16>(unpack_high_i16_m128i(v.b.sse, v.b.sse))
213 },
214 },
215 }
216 } else {
217 let arr = v.as_array();
219 Self::new([
220 arr[0] as u32, arr[1] as u32, arr[2] as u32, arr[3] as u32,
221 arr[4] as u32, arr[5] as u32, arr[6] as u32, arr[7] as u32,
222 arr[8] as u32, arr[9] as u32, arr[10] as u32, arr[11] as u32,
223 arr[12] as u32, arr[13] as u32, arr[14] as u32, arr[15] as u32,
224 ])
225 }
226 }
227 }
228}
229
230macro_rules! impl_shl_t_for_u32x16 {
231 ($($shift_type:ty),+ $(,)?) => {
232 $(impl Shl<$shift_type> for u32x16 {
233 type Output = Self;
234 #[inline]
236 fn shl(self, rhs: $shift_type) -> Self::Output {
237 pick! {
238 if #[cfg(target_feature="avx512f")] {
239 let shift = cast(rhs as u32);
240 Self { avx512: shl_all_u32_m512i(self.avx512, shift) }
241 } else {
242 Self {
243 a : self.a.shl(rhs),
244 b : self.b.shl(rhs),
245 }
246 }
247 }
248 }
249 })+
250 };
251}
252impl_shl_t_for_u32x16!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
253
254macro_rules! impl_shr_t_for_u32x16 {
255 ($($shift_type:ty),+ $(,)?) => {
256 $(impl Shr<$shift_type> for u32x16 {
257 type Output = Self;
258 #[inline]
260 fn shr(self, rhs: $shift_type) -> Self::Output {
261 pick! {
262 if #[cfg(target_feature="avx512f")] {
263 let shift = cast(rhs as u32);
264 Self { avx512: shr_all_u32_m512i(self.avx512, shift) }
265 } else {
266 Self {
267 a : self.a.shr(rhs),
268 b : self.b.shr(rhs),
269 }
270 }
271 }
272 }
273 })+
274 };
275}
276impl_shr_t_for_u32x16!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
277
278impl Shr<u32x16> for u32x16 {
284 type Output = Self;
285
286 #[inline]
287 fn shr(self, rhs: u32x16) -> Self::Output {
288 pick! {
289 if #[cfg(target_feature="avx512f")] {
290 let shift_by = bitand_m512i(rhs.avx512, set_splat_i32_m512i(31));
291 Self { avx512: shr_each_u32_m512i(self.avx512, shift_by ) }
292 } else {
293 Self {
294 a : self.a.shr(rhs.a),
295 b : self.b.shr(rhs.b),
296 }
297 }
298 }
299 }
300}
301
302impl Shl<u32x16> for u32x16 {
308 type Output = Self;
309
310 #[inline]
311 fn shl(self, rhs: u32x16) -> Self::Output {
312 pick! {
313 if #[cfg(target_feature="avx512f")] {
314 let shift_by = bitand_m512i(rhs.avx512, set_splat_i32_m512i(31));
315 Self { avx512: shl_each_u32_m512i(self.avx512, shift_by) }
316 } else {
317 Self {
318 a : self.a.shl(rhs.a),
319 b : self.b.shl(rhs.b),
320 }
321 }
322 }
323 }
324}
325
326#[expect(deprecated)]
327impl CmpEq for u32x16 {
328 type Output = Self;
329 #[inline]
330 fn simd_eq(self, rhs: Self) -> Self::Output {
331 pick! {
332 if #[cfg(target_feature="avx512f")] {
333 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Eq)}>(self.avx512, rhs.avx512) }
334 } else {
335 Self {
336 a : self.a.simd_eq(rhs.a),
337 b : self.b.simd_eq(rhs.b),
338 }
339 }
340 }
341 }
342}
343
344#[expect(deprecated)]
345impl CmpGt for u32x16 {
346 type Output = Self;
347 #[inline]
348 fn simd_gt(self, rhs: Self) -> Self::Output {
349 pick! {
350 if #[cfg(target_feature="avx512f")] {
351 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Nle)}>(self.avx512, rhs.avx512) }
352 } else {
353 Self {
354 a : self.a.simd_gt(rhs.a),
355 b : self.b.simd_gt(rhs.b),
356 }
357 }
358 }
359 }
360}
361
362#[expect(deprecated)]
363impl CmpLt for u32x16 {
364 type Output = Self;
365 #[inline]
366 fn simd_lt(self, rhs: Self) -> Self::Output {
367 pick! {
368 if #[cfg(target_feature="avx512f")] {
369 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Lt)}>(self.avx512, rhs.avx512) }
370 } else {
371 Self {
372 a : rhs.a.simd_gt(self.a),
373 b : rhs.b.simd_gt(self.b),
374 }
375 }
376 }
377 }
378}
379
380#[expect(deprecated)]
381impl CmpNe for u32x16 {
382 type Output = Self;
383 #[inline]
384 fn simd_ne(self, rhs: Self) -> Self::Output {
385 pick! {
386 if #[cfg(target_feature="avx512f")] {
387 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Ne)}>(self.avx512, rhs.avx512) }
388 } else {
389 Self {
390 a : self.a.simd_ne(rhs.a),
391 b : self.b.simd_ne(rhs.b),
392 }
393 }
394 }
395 }
396}
397
398#[expect(deprecated)]
399impl CmpLe for u32x16 {
400 type Output = Self;
401 #[inline]
402 fn simd_le(self, rhs: Self) -> Self::Output {
403 pick! {
404 if #[cfg(target_feature="avx512f")] {
405 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Le)}>(self.avx512, rhs.avx512) }
406 } else {
407 Self {
408 a : self.a.simd_le(rhs.a),
409 b : self.b.simd_le(rhs.b),
410 }
411 }
412 }
413 }
414}
415
416#[expect(deprecated)]
417impl CmpGe for u32x16 {
418 type Output = Self;
419 #[inline]
420 fn simd_ge(self, rhs: Self) -> Self::Output {
421 pick! {
422 if #[cfg(target_feature="avx512f")] {
423 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Nlt)}>(self.avx512, rhs.avx512) }
424 } else {
425 Self {
426 a : self.a.simd_ge(rhs.a),
427 b : self.b.simd_ge(rhs.b),
428 }
429 }
430 }
431 }
432}
433
434impl u32x16 {
435 #[inline]
436 #[must_use]
437 pub const fn new(array: [u32; 16]) -> Self {
438 unsafe { core::mem::transmute(array) }
439 }
440
441 simd_comparison_fns!();
442
443 #[inline]
444 #[must_use]
445 pub fn blend(self, t: Self, f: Self) -> Self {
446 pick! {
447 if #[cfg(target_feature="avx512f")] {
448 Self { avx512: blend_varying_i8_m512i(f.avx512,t.avx512,movepi8_mask_m512i(self.avx512)) }
449 } else {
450 Self {
451 a : self.a.blend(t.a, f.a),
452 b : self.b.blend(t.b, f.b),
453 }
454 }
455 }
456 }
457
458 #[inline]
459 #[must_use]
460 pub fn reduce_add(self) -> u32 {
461 cast(i32x16::reduce_add(cast(self)))
462 }
463
464 #[inline]
465 #[must_use]
466 pub fn reduce_max(self) -> u32 {
467 let array: [u32x8; 2] = cast(self);
468 array[0].max(array[1]).reduce_max()
469 }
470
471 #[inline]
472 #[must_use]
473 pub fn reduce_min(self) -> u32 {
474 let array: [u32x8; 2] = cast(self);
475 array[0].min(array[1]).reduce_min()
476 }
477
478 #[inline]
479 #[must_use]
480 pub fn min(self, rhs: Self) -> Self {
481 pick! {
482 if #[cfg(target_feature="avx512f")] {
483 Self { avx512: min_u32_m512i(self.avx512, rhs.avx512) }
484 } else {
485 Self {
486 a: self.a.min(rhs.a),
487 b: self.b.min(rhs.b),
488 }
489 }
490 }
491 }
492
493 #[inline]
494 #[must_use]
495 pub fn max(self, rhs: Self) -> Self {
496 pick! {
497 if #[cfg(target_feature="avx512f")] {
498 Self { avx512: max_u32_m512i(self.avx512, rhs.avx512) }
499 } else {
500 Self {
501 a: self.a.max(rhs.a),
502 b: self.b.max(rhs.b),
503 }
504 }
505 }
506 }
507
508 integer_fn_clamp!();
509
510 #[inline]
511 #[must_use]
512 pub fn saturating_add(self, rhs: Self) -> Self {
513 pick! {
514 if #[cfg(target_feature="avx512f")] {
515 let result = self + rhs;
516 result.simd_lt(self).blend(Self::MAX, result)
517 } else {
518 Self {
519 a: self.a.saturating_add(rhs.a),
520 b: self.b.saturating_add(rhs.b),
521 }
522 }
523 }
524 }
525
526 #[inline]
527 #[must_use]
528 pub fn saturating_sub(self, rhs: Self) -> Self {
529 pick! {
530 if #[cfg(target_feature="avx512f")] {
531 let result = self - rhs;
532 result.simd_gt(self).blend(Self::MIN, result)
533 } else {
534 Self {
535 a: self.a.saturating_sub(rhs.a),
536 b: self.b.saturating_sub(rhs.b),
537 }
538 }
539 }
540 }
541
542 #[inline]
544 #[must_use]
545 pub fn saturating_mul(self, rhs: Self) -> Self {
546 pick! {
547 if #[cfg(all(target_feature="avx512f", target_feature="avx512dq"))] {
548 #[cfg(target_arch = "x86")]
549 use core::arch::x86::{_mm512_unpackhi_epi64, _mm512_unpacklo_epi64};
550 #[cfg(target_arch = "x86_64")]
551 use core::arch::x86_64::{_mm512_unpackhi_epi64, _mm512_unpacklo_epi64};
552
553 let even_wide_mul = mul_u32_wide_m512i(self.avx512, rhs.avx512);
554 let odd_wide_mul = mul_u32_wide_m512i(
555 shuffle_i32_m512i::<0b_00_11_00_01>(self.avx512),
556 shuffle_i32_m512i::<0b_00_11_00_01>(rhs.avx512),
557 );
558
559 let ll_hh_1 = unpack_low_i32_m512i(even_wide_mul, odd_wide_mul);
560 let ll_hh_2 = unpack_high_i32_m512i(even_wide_mul, odd_wide_mul);
561 let low = Self {
563 avx512: m512i(unsafe { _mm512_unpacklo_epi64(ll_hh_1.0, ll_hh_2.0) }),
564 };
565 let high = Self {
566 avx512: m512i(unsafe { _mm512_unpackhi_epi64(ll_hh_1.0, ll_hh_2.0) }),
567 };
568
569 let no_overflow = high.simd_eq(Self::ZERO);
570 no_overflow.blend(low, Self::MAX)
571 } else {
572 let [self_a, self_b]: [u32x8; 2] = cast(self);
573 let [rhs_a, rhs_b]: [u32x8; 2] = cast(rhs);
574
575 cast([self_a.saturating_mul(rhs_a), self_b.saturating_mul(rhs_b)])
576 }
577 }
578 }
579
580 integer_fn_saturating_div!([
581 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
582 ]);
583
584 #[inline]
585 #[must_use]
586 pub fn mul_keep_high(self, rhs: Self) -> Self {
587 pick! {
588 if #[cfg(target_feature="avx512f")] {
589 let alo = extract_m256i32_from_m512i::<0>(self.avx512);
590 let ahi = extract_m256i32_from_m512i::<1>(self.avx512);
591 let blo = extract_m256i32_from_m512i::<0>(rhs.avx512);
592 let bhi = extract_m256i32_from_m512i::<1>(rhs.avx512);
593
594 let lo_res: m256i = {
595 let a8 = u32x8 { avx2: alo };
596 let b8 = u32x8 { avx2: blo };
597 a8.mul_keep_high(b8).avx2
598 };
599 let hi_res: m256i = {
600 let a8 = u32x8 { avx2: ahi };
601 let b8 = u32x8 { avx2: bhi };
602 a8.mul_keep_high(b8).avx2
603 };
604
605 let zero = zeroed_m512i();
606 let with_lo = insert_m256i32_to_m512i::<0>(zero, lo_res);
607 let combined = insert_m256i32_to_m512i::<1>(with_lo, hi_res);
608
609 Self { avx512: combined }
610 } else {
611 Self {
612 a: self.a.mul_keep_high(rhs.a),
613 b: self.b.mul_keep_high(rhs.b),
614 }
615 }
616 }
617 }
618
619 #[inline]
620 #[must_use]
621 #[doc(alias("movemask", "move_mask"))]
622 pub fn to_bitmask(self) -> u32 {
623 i32x16::to_bitmask(cast(self))
624 }
625
626 #[inline]
627 #[must_use]
628 pub fn any(self) -> bool {
629 i32x16::any(cast(self))
630 }
631
632 #[inline]
633 #[must_use]
634 pub fn all(self) -> bool {
635 i32x16::all(cast(self))
636 }
637
638 #[inline]
639 #[must_use]
640 pub fn none(self) -> bool {
641 i32x16::none(cast(self))
642 }
643
644 #[must_use]
646 #[inline]
647 pub fn transpose(data: [u32x16; 16]) -> [u32x16; 16] {
648 cast(i32x16::transpose(cast(data)))
649 }
650
651 #[inline]
652 pub fn to_array(self) -> [u32; 16] {
653 cast(self)
654 }
655
656 #[inline]
657 pub fn as_array(&self) -> &[u32; 16] {
658 cast_ref(self)
659 }
660
661 #[inline]
662 pub fn as_mut_array(&mut self) -> &mut [u32; 16] {
663 cast_mut(self)
664 }
665}
666
667impl Not for u32x16 {
668 type Output = Self;
669 #[inline]
670 fn not(self) -> Self::Output {
671 pick! {
672 if #[cfg(target_feature="avx512f")] {
673 Self { avx512: bitxor_m512i(self.avx512, set_splat_i32_m512i(-1)) }
674 } else {
675 Self {
676 a : self.a.not(),
677 b : self.b.not(),
678 }
679 }
680 }
681 }
682}