1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx512f")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
12 #[repr(C, align(64))]
13 pub struct u32x16 { pub(crate) avx512: m512i }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq, Eq)]
22 #[repr(C, align(64))]
23 pub struct u32x16 { pub(crate) a : u32x8, pub(crate) b : u32x8 }
24 }
25}
26
27impl_simd_uint! {
28 unsafe {
29 T = u32,
30 N = 16,
31 Simd = u32x16,
32 IntSimd = i32x16,
33 T_BITS = 32,
34 T_BITS_MUL_2 = 64,
35 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
36 optional_type_x86_inner { X86Inner = __m512i },
37 optional_type_arm_inner {},
38 optional_type_wasm_inner {},
39 }
40
41 #[inline]
42 fn not(self) -> Self::Output {
43 pick! {
44 if #[cfg(target_feature="avx512f")] {
45 Self { avx512: bitxor_m512i(self.avx512, set_splat_i32_m512i(-1)) }
46 } else {
47 Self {
48 a : self.a.not(),
49 b : self.b.not(),
50 }
51 }
52 }
53 }
54
55 #[inline]
56 fn add(self, rhs: Self) -> Self::Output {
57 pick! {
58 if #[cfg(target_feature="avx512f")] {
59 Self { avx512: add_i32_m512i(self.avx512, rhs.avx512) }
60 } else {
61 Self {
62 a : self.a.add(rhs.a),
63 b : self.b.add(rhs.b),
64 }
65 }
66 }
67 }
68
69 #[inline]
70 fn sub(self, rhs: Self) -> Self::Output {
71 pick! {
72 if #[cfg(target_feature="avx512f")] {
73 Self { avx512: sub_i32_m512i(self.avx512, rhs.avx512) }
74 } else {
75 Self {
76 a : self.a.sub(rhs.a),
77 b : self.b.sub(rhs.b),
78 }
79 }
80 }
81 }
82
83 #[inline]
84 fn mul(self, rhs: Self) -> Self::Output {
85 pick! {
86 if #[cfg(target_feature="avx512f")] {
87 Self { avx512: mul_i32_keep_low_m512i(self.avx512, rhs.avx512) }
88 } else {
89 Self {
90 a : self.a.mul(rhs.a),
91 b : self.b.mul(rhs.b),
92 }
93 }
94 }
95 }
96
97 #[inline]
98 fn bitand(self, rhs: Self) -> Self::Output {
99 pick! {
100 if #[cfg(target_feature="avx512f")] {
101 Self { avx512: bitand_m512i(self.avx512, rhs.avx512) }
102 } else {
103 Self {
104 a : self.a.bitand(rhs.a),
105 b : self.b.bitand(rhs.b),
106 }
107 }
108 }
109 }
110
111 #[inline]
112 fn bitor(self, rhs: Self) -> Self::Output {
113 pick! {
114 if #[cfg(target_feature="avx512f")] {
115 Self { avx512: bitor_m512i(self.avx512, rhs.avx512) }
116 } else {
117 Self {
118 a : self.a.bitor(rhs.a),
119 b : self.b.bitor(rhs.b),
120 }
121 }
122 }
123 }
124
125 #[inline]
126 fn bitxor(self, rhs: Self) -> Self::Output {
127 pick! {
128 if #[cfg(target_feature="avx512f")] {
129 Self { avx512: bitxor_m512i(self.avx512, rhs.avx512) }
130 } else {
131 Self {
132 a : self.a.bitxor(rhs.a),
133 b : self.b.bitxor(rhs.b),
134 }
135 }
136 }
137 }
138
139 #[inline]
140 fn simd_eq(self, rhs: Self) -> Self::Output {
141 pick! {
142 if #[cfg(target_feature="avx512f")] {
143 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Eq)}>(self.avx512, rhs.avx512) }
144 } else {
145 Self {
146 a : self.a.simd_eq(rhs.a),
147 b : self.b.simd_eq(rhs.b),
148 }
149 }
150 }
151 }
152
153 #[inline]
154 fn simd_ne(self, rhs: Self) -> Self::Output {
155 pick! {
156 if #[cfg(target_feature="avx512f")] {
157 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Ne)}>(self.avx512, rhs.avx512) }
158 } else {
159 Self {
160 a : self.a.simd_ne(rhs.a),
161 b : self.b.simd_ne(rhs.b),
162 }
163 }
164 }
165 }
166
167 #[inline]
168 fn simd_lt(self, rhs: Self) -> Self::Output {
169 pick! {
170 if #[cfg(target_feature="avx512f")] {
171 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Lt)}>(self.avx512, rhs.avx512) }
172 } else {
173 Self {
174 a : rhs.a.simd_gt(self.a),
175 b : rhs.b.simd_gt(self.b),
176 }
177 }
178 }
179 }
180
181 #[inline]
182 fn simd_gt(self, rhs: Self) -> Self::Output {
183 pick! {
184 if #[cfg(target_feature="avx512f")] {
185 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Nle)}>(self.avx512, rhs.avx512) }
186 } else {
187 Self {
188 a : self.a.simd_gt(rhs.a),
189 b : self.b.simd_gt(rhs.b),
190 }
191 }
192 }
193 }
194
195 #[inline]
196 fn simd_le(self, rhs: Self) -> Self::Output {
197 pick! {
198 if #[cfg(target_feature="avx512f")] {
199 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Le)}>(self.avx512, rhs.avx512) }
200 } else {
201 Self {
202 a : self.a.simd_le(rhs.a),
203 b : self.b.simd_le(rhs.b),
204 }
205 }
206 }
207 }
208
209 #[inline]
210 fn simd_ge(self, rhs: Self) -> Self::Output {
211 pick! {
212 if #[cfg(target_feature="avx512f")] {
213 Self { avx512: cmp_op_mask_u32_m512i::<{cmp_int_op!(Nlt)}>(self.avx512, rhs.avx512) }
214 } else {
215 Self {
216 a : self.a.simd_ge(rhs.a),
217 b : self.b.simd_ge(rhs.b),
218 }
219 }
220 }
221 }
222
223 #[inline]
224 pub fn reduce_add(self) -> u32 {
225 let array: [u32x8; 2] = cast(self);
226 (array[0] + array[1]).reduce_add()
227 }
228
229 #[inline]
230 pub fn reduce_mul(self) -> u32 {
231 let array: [u32x8; 2] = cast(self);
232 (array[0] * array[1]).reduce_mul()
233 }
234
235 #[inline]
236 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
237 pick! {
238 if #[cfg(target_feature="avx512f")] {
239 Self {
240 avx512: bitor_m512i(
241 bitand_m512i(if_one.avx512, self.avx512),
242 bitandnot_m512i(self.avx512, if_zero.avx512),
243 ),
244 }
245 } else {
246 Self {
247 a: self.a.bitselect(if_one.a, if_zero.a),
248 b: self.b.bitselect(if_one.b, if_zero.b),
249 }
250 }
251 }
252 }
253
254 #[inline]
255 fn select(self, if_true: Self, if_false: Self) -> Self {
256 pick! {
257 if #[cfg(target_feature="avx512f")] {
258 Self { avx512: blend_varying_i8_m512i(if_false.avx512,if_true.avx512,movepi8_mask_m512i(self.avx512)) }
259 } else {
260 Self {
261 a : self.a.select(if_true.a, if_false.a),
262 b : self.b.select(if_true.b, if_false.b),
263 }
264 }
265 }
266 }
267
268 #[inline]
269 pub fn to_bitmask(self) -> u32 {
270 pick! {
271 if #[cfg(target_feature="avx512dq")] {
272 movepi32_mask_m512i(self.avx512) as u32
273 } else {
274 f32x16::to_bitmask(cast(self))
275 }
276 }
277 }
278
279 #[inline]
280 pub fn any(self) -> bool {
281 pick! {
282 if #[cfg(target_feature="avx512bw")] {
283 movepi32_mask_m512i(self.avx512) != 0
284 } else {
285 let [a, b]: [u32x8; 2] = cast(self);
286 (a | b).any()
287 }
288 }
289 }
290
291 #[inline]
292 pub fn all(self) -> bool {
293 pick! {
294 if #[cfg(target_feature="avx512bw")] {
295 movepi32_mask_m512i(self.avx512) == 0xFFFF
296 } else {
297 let [a, b]: [u32x8; 2] = cast(self);
298 (a & b).all()
299 }
300 }
301 }
302
303 #[inline]
304 pub fn shuffle(self, indices: u32x16) -> Self {
305 pick! {
306 if #[cfg(all(target_feature = "avx512f"))] {
307 Self { avx512: permute_i32_m512i(indices.avx512, self.avx512) }
308 } else {
309 let self_halfs = cast::<u32x16, [u32x8; 2]>(self);
310 let [indices_a, indices_b] = cast::<u32x16, [u32x8; 2]>(indices);
311
312 cast([self_halfs.shuffle(indices_a), self_halfs.shuffle(indices_b)])
313 }
314 }
315 }
316
317 #[inline]
318 pub fn shuffle_zeroing(self, indices: u32x16) -> Self {
319 pick! {
320 if #[cfg(all(target_feature = "avx512f"))] {
321 self.shuffle(indices) & indices.simd_lt(16)
322 } else {
323 let self_halfs = cast::<u32x16, [u32x8; 2]>(self);
324 let [indices_a, indices_b] = cast::<u32x16, [u32x8; 2]>(indices);
325
326 cast([self_halfs.shuffle_zeroing(indices_a), self_halfs.shuffle_zeroing(indices_b)])
327 }
328 }
329 }
330
331 #[inline]
332 pub fn shuffle_wrapping(self, indices: u32x16) -> Self {
333 pick! {
334 if #[cfg(all(target_feature = "avx512f"))] {
335 self.shuffle(indices)
337 } else {
338 let self_halfs = cast::<u32x16, [u32x8; 2]>(self);
339 let [indices_a, indices_b] = cast::<u32x16, [u32x8; 2]>(indices);
340
341 cast([self_halfs.shuffle_wrapping(indices_a), self_halfs.shuffle_wrapping(indices_b)])
342 }
343 }
344 }
345
346 #[inline]
347 fn shuffle(self: [u32x16; 2], indices: u32x16) -> u32x16 {
348 pick! {
349 if #[cfg(all(target_feature = "avx512f"))] {
350 u32x16 { avx512: shuffle_abv_i32_all_m512i(self[0].avx512, indices.avx512, self[1].avx512) }
351 } else {
352 self[0].shuffle_zeroing(indices) | self[1].shuffle_zeroing(indices - 16)
353 }
354 }
355 }
356
357 #[inline]
358 fn shuffle_zeroing(self: [u32x16; 2], indices: u32x16) -> u32x16 {
359 pick! {
360 if #[cfg(all(target_feature = "avx512f"))] {
361 self.shuffle(indices) & indices.simd_lt(32)
362 } else {
363 self.shuffle(indices)
364 }
365 }
366 }
367
368 #[inline]
369 fn shuffle_wrapping(self: [u32x16; 2], indices: u32x16) -> u32x16 {
370 pick! {
371 if #[cfg(all(target_feature = "avx512f", target_feature = "avx512vl"))] {
372 self.shuffle(indices)
374 } else {
375 self.shuffle(indices & 31)
376 }
377 }
378 }
379
380 #[inline]
381 fn shuffle(self: [u32x16; 3], indices: u32x16) -> u32x16 {
382 [self[0], self[1]].shuffle_zeroing(indices) | self[2].shuffle_zeroing(indices - 32)
383 }
384
385 #[inline]
386 fn shuffle_zeroing(self: [u32x16; 3], indices: u32x16) -> u32x16 {
387 self.shuffle(indices)
388 }
389
390 #[inline]
391 fn shuffle_wrapping(self: [u32x16; 3], indices: u32x16) -> u32x16 {
392 self.shuffle(indices % 48)
393 }
394
395 #[inline]
396 fn shuffle(self: [u32x16; 4], indices: u32x16) -> u32x16 {
397 [self[0], self[1]].shuffle_zeroing(indices) | [self[2], self[3]].shuffle_zeroing(indices - 32)
398 }
399
400 #[inline]
401 fn shuffle_zeroing(self: [u32x16; 4], indices: u32x16) -> u32x16 {
402 self.shuffle(indices)
403 }
404
405 #[inline]
406 fn shuffle_wrapping(self: [u32x16; 4], indices: u32x16) -> u32x16 {
407 self.shuffle(indices & 63)
408 }
409
410 #[inline]
413 pub fn transpose(data: [Self; 16]) -> [Self; 16] {
414 #[inline(always)]
417 fn transpose_column(data: &[u32x16; 16], index: usize) -> u32x16 {
418 u32x16::new([
419 data[0].as_array()[index],
420 data[1].as_array()[index],
421 data[2].as_array()[index],
422 data[3].as_array()[index],
423 data[4].as_array()[index],
424 data[5].as_array()[index],
425 data[6].as_array()[index],
426 data[7].as_array()[index],
427 data[8].as_array()[index],
428 data[9].as_array()[index],
429 data[10].as_array()[index],
430 data[11].as_array()[index],
431 data[12].as_array()[index],
432 data[13].as_array()[index],
433 data[14].as_array()[index],
434 data[15].as_array()[index],
435 ])
436 }
437
438 [
439 transpose_column(&data, 0),
440 transpose_column(&data, 1),
441 transpose_column(&data, 2),
442 transpose_column(&data, 3),
443 transpose_column(&data, 4),
444 transpose_column(&data, 5),
445 transpose_column(&data, 6),
446 transpose_column(&data, 7),
447 transpose_column(&data, 8),
448 transpose_column(&data, 9),
449 transpose_column(&data, 10),
450 transpose_column(&data, 11),
451 transpose_column(&data, 12),
452 transpose_column(&data, 13),
453 transpose_column(&data, 14),
454 transpose_column(&data, 15),
455 ]
456 }
457
458 #[inline]
459 fn shl(self, rhs: u32x16) -> Self::Output {
460 pick! {
461 if #[cfg(target_feature="avx512f")] {
462 let shift_by = bitand_m512i(rhs.avx512, set_splat_i32_m512i(31));
463 Self { avx512: shl_each_u32_m512i(self.avx512, shift_by) }
464 } else {
465 Self {
466 a : self.a.shl(rhs.a),
467 b : self.b.shl(rhs.b),
468 }
469 }
470 }
471 }
472
473 #[inline]
474 fn shl(self, rhs: u32) -> Self::Output {
475 pick! {
476 if #[cfg(target_feature="avx512f")] {
477 #[expect(clippy::suspicious_arithmetic_impl)]
479 let shift = rhs & 31;
480 Self { avx512: shl_all_u32_m512i(self.avx512, shift) }
481 } else {
482 Self {
483 a : self.a.shl(rhs),
484 b : self.b.shl(rhs),
485 }
486 }
487 }
488 }
489
490 #[inline]
491 fn shr(self, rhs: u32x16) -> Self::Output {
492 pick! {
493 if #[cfg(target_feature="avx512f")] {
494 let shift_by = bitand_m512i(rhs.avx512, set_splat_i32_m512i(31));
495 Self { avx512: shr_each_u32_m512i(self.avx512, shift_by ) }
496 } else {
497 Self {
498 a : self.a.shr(rhs.a),
499 b : self.b.shr(rhs.b),
500 }
501 }
502 }
503 }
504
505 #[inline]
506 fn shr(self, rhs: u32) -> Self::Output {
507 pick! {
508 if #[cfg(target_feature="avx512f")] {
509 #[expect(clippy::suspicious_arithmetic_impl)]
511 let shift = rhs & 31;
512 Self { avx512: shr_all_u32_m512i(self.avx512, shift) }
513 } else {
514 Self {
515 a : self.a.shr(rhs),
516 b : self.b.shr(rhs),
517 }
518 }
519 }
520 }
521
522 #[inline]
523 pub fn max(self, rhs: Self) -> Self {
524 pick! {
525 if #[cfg(target_feature="avx512f")] {
526 Self { avx512: max_u32_m512i(self.avx512, rhs.avx512) }
527 } else {
528 Self {
529 a: self.a.max(rhs.a),
530 b: self.b.max(rhs.b),
531 }
532 }
533 }
534 }
535
536 #[inline]
537 pub fn min(self, rhs: Self) -> Self {
538 pick! {
539 if #[cfg(target_feature="avx512f")] {
540 Self { avx512: min_u32_m512i(self.avx512, rhs.avx512) }
541 } else {
542 Self {
543 a: self.a.min(rhs.a),
544 b: self.b.min(rhs.b),
545 }
546 }
547 }
548 }
549
550 #[inline]
551 pub fn reduce_max(self) -> u32 {
552 let array: [u32x8; 2] = cast(self);
553 array[0].max(array[1]).reduce_max()
554 }
555
556 #[inline]
557 pub fn reduce_min(self) -> u32 {
558 let array: [u32x8; 2] = cast(self);
559 array[0].min(array[1]).reduce_min()
560 }
561
562 #[inline]
563 pub fn unbounded_shl(self, rhs: Self) -> Self {
564 pick! {
565 if #[cfg(target_feature="avx512f")] {
566 Self { avx512: shl_each_u32_m512i(self.avx512, rhs.avx512) }
567 } else {
568 Self {
569 a: self.a.unbounded_shl(rhs.a),
570 b: self.b.unbounded_shl(rhs.b),
571 }
572 }
573 }
574 }
575
576 #[inline]
577 pub fn unbounded_shl_scalar(self, rhs: u32) -> Self {
578 pick! {
579 if #[cfg(target_feature="avx512f")] {
580 Self { avx512: shl_all_u32_m512i(self.avx512, rhs) }
581 } else {
582 Self {
583 a: self.a.unbounded_shl_scalar(rhs),
584 b: self.b.unbounded_shl_scalar(rhs),
585 }
586 }
587 }
588 }
589
590 #[inline]
591 pub fn unbounded_shr(self, rhs: Self) -> Self {
592 pick! {
593 if #[cfg(target_feature="avx512f")] {
594 Self { avx512: shr_each_u32_m512i(self.avx512, rhs.avx512) }
595 } else {
596 Self {
597 a: self.a.unbounded_shr(rhs.a),
598 b: self.b.unbounded_shr(rhs.b),
599 }
600 }
601 }
602 }
603
604 #[inline]
605 pub fn unbounded_shr_scalar(self, rhs: u32) -> Self {
606 pick! {
607 if #[cfg(target_feature="avx512f")] {
608 Self { avx512: shr_all_u32_m512i(self.avx512, rhs) }
609 } else {
610 Self {
611 a: self.a.unbounded_shr_scalar(rhs),
612 b: self.b.unbounded_shr_scalar(rhs),
613 }
614 }
615 }
616 }
617
618 #[inline]
619 pub fn saturating_add(self, rhs: Self) -> Self {
620 pick! {
621 if #[cfg(target_feature="avx512f")] {
622 let result = self + rhs;
623 let overflow = result.simd_lt(self);
624 result | overflow
626 } else {
627 Self {
628 a: self.a.saturating_add(rhs.a),
629 b: self.b.saturating_add(rhs.b),
630 }
631 }
632 }
633 }
634
635 #[inline]
636 pub fn saturating_sub(self, rhs: Self) -> Self {
637 pick! {
638 if #[cfg(target_feature="avx512f")] {
639 let result = self - rhs;
640 let no_overflow = result.simd_le(self);
641 result & no_overflow
643 } else {
644 Self {
645 a: self.a.saturating_sub(rhs.a),
646 b: self.b.saturating_sub(rhs.b),
647 }
648 }
649 }
650 }
651
652 #[inline]
653 pub fn overflowing_mul(self, rhs: Self) -> (Self, Self) {
654 let (low, high) = self.mul_keep_low_high(rhs);
655 let overflow = high.simd_ne(Self::ZERO);
656 (low, overflow)
657 }
658
659 optional_fn_widening_mul {
660 }
662
663 #[inline]
664 pub fn mul_keep_low_high(self, rhs: Self) -> (Self, Self) {
665 pick! {
666 if #[cfg(all(target_feature="avx512f", target_feature="avx512dq"))] {
667 #[cfg(target_arch = "x86")]
668 use core::arch::x86::{_mm512_unpackhi_epi64, _mm512_unpacklo_epi64};
669 #[cfg(target_arch = "x86_64")]
670 use core::arch::x86_64::{_mm512_unpackhi_epi64, _mm512_unpacklo_epi64};
671
672 let even_wide_mul = mul_u32_wide_m512i(self.avx512, rhs.avx512);
673 let odd_wide_mul = mul_u32_wide_m512i(
674 shuffle_i32_m512i::<0b_00_11_00_01>(self.avx512),
675 shuffle_i32_m512i::<0b_00_11_00_01>(rhs.avx512),
676 );
677
678 let ll_hh_1 = unpack_low_i32_m512i(even_wide_mul, odd_wide_mul);
679 let ll_hh_2 = unpack_high_i32_m512i(even_wide_mul, odd_wide_mul);
680 (
682 Self {
683 avx512: m512i(unsafe { _mm512_unpacklo_epi64(ll_hh_1.0, ll_hh_2.0) }),
684 },
685 Self {
686 avx512: m512i(unsafe { _mm512_unpackhi_epi64(ll_hh_1.0, ll_hh_2.0) }),
687 },
688 )
689 } else {
690 let [self_a, self_b] = cast::<u32x16, [u32x8; 2]>(self);
691 let [rhs_a, rhs_b] = cast::<u32x16, [u32x8; 2]>(rhs);
692
693 let result_a = self_a.mul_keep_low_high(rhs_a);
694 let result_b = self_b.mul_keep_low_high(rhs_b);
695 (
696 cast([result_a.0, result_b.0]),
697 cast([result_a.1, result_b.1]),
698 )
699 }
700 }
701 }
702
703 #[inline]
704 pub fn mul_keep_high(self, rhs: Self) -> Self {
705 pick! {
706 if #[cfg(target_feature="avx512f")] {
707 let alo = extract_m256i32_from_m512i::<0>(self.avx512);
708 let ahi = extract_m256i32_from_m512i::<1>(self.avx512);
709 let blo = extract_m256i32_from_m512i::<0>(rhs.avx512);
710 let bhi = extract_m256i32_from_m512i::<1>(rhs.avx512);
711
712 let lo_res: m256i = {
713 let a8 = u32x8 { avx2: alo };
714 let b8 = u32x8 { avx2: blo };
715 a8.mul_keep_high(b8).avx2
716 };
717 let hi_res: m256i = {
718 let a8 = u32x8 { avx2: ahi };
719 let b8 = u32x8 { avx2: bhi };
720 a8.mul_keep_high(b8).avx2
721 };
722
723 let zero = zeroed_m512i();
724 let with_lo = insert_m256i32_to_m512i::<0>(zero, lo_res);
725 let combined = insert_m256i32_to_m512i::<1>(with_lo, hi_res);
726
727 Self { avx512: combined }
728 } else {
729 Self {
730 a: self.a.mul_keep_high(rhs.a),
731 b: self.b.mul_keep_high(rhs.b),
732 }
733 }
734 }
735 }
736
737 optional_fn_deserialize {}
738}
739
740impl From<u16x16> for u32x16 {
741 #[inline]
743 fn from(v: u16x16) -> Self {
744 pick! {
745 if #[cfg(target_feature = "avx512f")] {
746 Self {
747 avx512: convert_to_u32_m512i_from_u16_m256i(v.avx2)
748 }
749 } else if #[cfg(target_feature = "avx2")] {
750 let lo: m128i = extract_m128i_from_m256i::<0>(v.avx2);
751 let hi: m128i = extract_m128i_from_m256i::<1>(v.avx2);
752 Self {
753 a: u32x8 { avx2: convert_to_i32_m256i_from_u16_m128i(lo) },
754 b: u32x8 { avx2: convert_to_i32_m256i_from_u16_m128i(hi) },
755 }
756 } else if #[cfg(target_feature = "sse2")] {
757 Self {
758 a: u32x8 {
759 a: u32x4 {
760 sse: shr_imm_u32_m128i::<16>(unpack_low_i16_m128i(v.a.sse, v.a.sse))
761 },
762 b: u32x4 {
763 sse: shr_imm_u32_m128i::<16>(unpack_high_i16_m128i(v.a.sse, v.a.sse))
764 },
765 },
766 b: u32x8 {
767 a: u32x4 {
768 sse: shr_imm_u32_m128i::<16>(unpack_low_i16_m128i(v.b.sse, v.b.sse))
769 },
770 b: u32x4 {
771 sse: shr_imm_u32_m128i::<16>(unpack_high_i16_m128i(v.b.sse, v.b.sse))
772 },
773 },
774 }
775 } else {
776 let arr = v.as_array();
778 Self::new([
779 arr[0] as u32, arr[1] as u32, arr[2] as u32, arr[3] as u32,
780 arr[4] as u32, arr[5] as u32, arr[6] as u32, arr[7] as u32,
781 arr[8] as u32, arr[9] as u32, arr[10] as u32, arr[11] as u32,
782 arr[12] as u32, arr[13] as u32, arr[14] as u32, arr[15] as u32,
783 ])
784 }
785 }
786 }
787}
788
789impl u32x16 {
792 #[inline]
795 #[must_use]
796 pub fn unpack_lo(self, b: Self) -> Self {
797 pick! {
798 if #[cfg(target_feature="avx512f")] {
799 let [aa, _]: [u32x8; 2] = cast(self);
802 let [ba, _]: [u32x8; 2] = cast(b);
803 cast([aa.unpack_lo(ba), aa.unpack_hi(ba)])
804 } else {
805 Self { a: self.a.unpack_lo(b.a), b: self.a.unpack_hi(b.a) }
806 }
807 }
808 }
809
810 #[inline]
813 #[must_use]
814 pub fn unpack_hi(self, b: Self) -> Self {
815 pick! {
816 if #[cfg(target_feature="avx512f")] {
817 let [_, ab]: [u32x8; 2] = cast(self);
820 let [_, bb]: [u32x8; 2] = cast(b);
821 cast([ab.unpack_lo(bb), ab.unpack_hi(bb)])
822 } else {
823 Self { a: self.b.unpack_lo(b.b), b: self.b.unpack_hi(b.b) }
824 }
825 }
826 }
827
828 #[inline]
835 #[must_use]
836 pub fn add_mul_lo<const W: u32>(self, a: Self, b: Self) -> Self {
837 if W <= 16 {
838 let mask = Self::splat(add_mul_operand_mask_u32::<W>());
839 return self + (((a & mask) * (b & mask)) & mask);
840 }
841
842 let acc = self.to_array();
843 let a = a.to_array();
844 let b = b.to_array();
845 Self::new(core::array::from_fn(|i| {
846 add_mul_lo_lane_u32::<W>(acc[i], a[i], b[i])
847 }))
848 }
849
850 #[inline]
853 #[must_use]
854 pub fn add_mul_hi<const W: u32>(self, a: Self, b: Self) -> Self {
855 if W <= 16 {
858 let mask = Self::splat(add_mul_operand_mask_u32::<W>());
859 return self + (((a & mask) * (b & mask)) >> W);
860 }
861
862 let acc = self.to_array();
863 let a = a.to_array();
864 let b = b.to_array();
865 Self::new(core::array::from_fn(|i| {
866 add_mul_hi_lane_u32::<W>(acc[i], a[i], b[i])
867 }))
868 }
869}