1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
12 #[repr(C, align(32))]
13 pub struct u8x32 { pub(crate) avx: m256i }
14 } else {
15 #[derive(Default, Clone, Copy, PartialEq, Eq)]
22 #[repr(C, align(32))]
23 pub struct u8x32 { pub(crate) a : u8x16, pub(crate) b : u8x16 }
24 }
25}
26
27impl_simd_uint! {
28 unsafe {
29 T = u8,
30 N = 32,
31 Simd = u8x32,
32 IntSimd = i8x32,
33 T_BITS = 8,
34 T_BITS_MUL_2 = 16,
35 [
36 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
37 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
38 ],
39 optional_type_x86_inner { X86Inner = __m256i },
40 optional_type_arm_inner {},
41 optional_type_wasm_inner {},
42 }
43
44 #[inline]
45 fn not(self) -> Self {
46 pick! {
47 if #[cfg(target_feature="avx2")] {
48 Self { avx: self.avx.not() }
49 } else {
50 Self {
51 a : self.a.not(),
52 b : self.b.not(),
53 }
54 }
55 }
56 }
57
58 #[inline]
59 fn add(self, rhs: Self) -> Self::Output {
60 pick! {
61 if #[cfg(target_feature="avx2")] {
62 Self { avx: add_i8_m256i(self.avx,rhs.avx) }
63 } else {
64 Self {
65 a : self.a.add(rhs.a),
66 b : self.b.add(rhs.b),
67 }
68 }
69 }
70 }
71
72 #[inline]
73 fn sub(self, rhs: Self) -> Self::Output {
74 pick! {
75 if #[cfg(target_feature="avx2")] {
76 Self { avx: sub_i8_m256i(self.avx,rhs.avx) }
77 } else {
78 Self {
79 a : self.a.sub(rhs.a),
80 b : self.b.sub(rhs.b),
81 }
82 }
83 }
84 }
85
86 #[inline]
87 fn mul(self, rhs: Self) -> Self::Output {
88 let [self_a, self_b]: [u8x16; 2] = cast(self);
92 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
93 cast([self_a * rhs_a, self_b * rhs_b])
94 }
95
96 #[inline]
97 fn bitand(self, rhs: Self) -> Self::Output {
98 pick! {
99 if #[cfg(target_feature="avx2")] {
100 Self { avx : bitand_m256i(self.avx,rhs.avx) }
101 } else {
102 Self {
103 a : self.a.bitand(rhs.a),
104 b : self.b.bitand(rhs.b),
105 }
106 }
107 }
108 }
109
110 #[inline]
111 fn bitor(self, rhs: Self) -> Self::Output {
112 pick! {
113 if #[cfg(target_feature="avx2")] {
114 Self { avx : bitor_m256i(self.avx,rhs.avx) }
115 } else {
116 Self {
117 a : self.a.bitor(rhs.a),
118 b : self.b.bitor(rhs.b),
119 }
120 }
121 }
122 }
123
124 #[inline]
125 fn bitxor(self, rhs: Self) -> Self::Output {
126 pick! {
127 if #[cfg(target_feature="avx2")] {
128 Self { avx : bitxor_m256i(self.avx,rhs.avx) }
129 } else {
130 Self {
131 a : self.a.bitxor(rhs.a),
132 b : self.b.bitxor(rhs.b),
133 }
134 }
135 }
136 }
137
138 #[inline]
139 fn simd_eq(self, rhs: Self) -> Self::Output {
140 pick! {
141 if #[cfg(target_feature="avx2")] {
142 Self { avx : cmp_eq_mask_i8_m256i(self.avx,rhs.avx) }
143 } else {
144 Self {
145 a : self.a.simd_eq(rhs.a),
146 b : self.b.simd_eq(rhs.b),
147 }
148 }
149 }
150 }
151
152 #[inline]
153 fn simd_ne(self, rhs: Self) -> Self::Output {
154 pick! {
155 if #[cfg(target_feature="avx2")] {
156 !self.simd_eq(rhs)
157 } else {
158 Self {
159 a : self.a.simd_ne(rhs.a),
160 b : self.b.simd_ne(rhs.b),
161 }
162 }
163 }
164 }
165
166 #[inline]
167 fn simd_lt(self, rhs: Self) -> Self::Output {
168 pick! {
169 if #[cfg(target_feature="avx2")] {
170 let offset = Self::splat(0x80);
172 let self_i8 = self.bitxor(offset).avx;
173 let rhs_i8 = rhs.bitxor(offset).avx;
174 Self { avx: cmp_gt_mask_i8_m256i(rhs_i8, self_i8)}
175 } else {
176 Self { a: self.a.simd_lt(rhs.a), b: self.b.simd_lt(rhs.b) }
177 }
178 }
179 }
180
181 #[inline]
182 fn simd_gt(self, rhs: Self) -> Self::Output {
183 pick! {
184 if #[cfg(target_feature="avx2")] {
185 let offset = Self::splat(0x80);
187 let self_i8 = self.bitxor(offset).avx;
188 let rhs_i8 = rhs.bitxor(offset).avx;
189 Self { avx : cmp_gt_mask_i8_m256i(self_i8,rhs_i8) }
190 } else {
191 Self { a: self.a.simd_gt(rhs.a), b: self.b.simd_gt(rhs.b) }
192 }
193 }
194 }
195
196 #[inline]
197 fn simd_le(self, rhs: Self) -> Self::Output {
198 pick! {
199 if #[cfg(target_feature="avx2")] {
200 let offset = Self::splat(0x80);
202 let self_i8 = self.bitxor(offset).avx;
203 let rhs_i8 = rhs.bitxor(offset).avx;
204 let gt_mask = Self { avx : cmp_gt_mask_i8_m256i(self_i8,rhs_i8) };
205 Self { avx: gt_mask.bitxor(Self::splat(0xFF)).avx }
206 } else {
207 Self { a: self.a.simd_le(rhs.a), b: self.b.simd_le(rhs.b) }
208 }
209 }
210 }
211
212 #[inline]
213 fn simd_ge(self, rhs: Self) -> Self::Output {
214 pick! {
215 if #[cfg(target_feature="avx2")] {
216 let offset = Self::splat(0x80);
218 let self_i8 = self.bitxor(offset).avx;
219 let rhs_i8 = rhs.bitxor(offset).avx;
220 let lt_mask = Self { avx: cmp_gt_mask_i8_m256i(rhs_i8, self_i8)};
221 Self { avx: lt_mask.bitxor(Self::splat(0xFF)).avx }
222 } else {
223 Self { a: self.a.simd_ge(rhs.a), b: self.b.simd_ge(rhs.b) }
224 }
225 }
226 }
227
228 #[inline]
229 pub fn reduce_add(self) -> u8 {
230 let array: [u8x16; 2] = cast(self);
231 (array[0] + array[1]).reduce_add()
232 }
233
234 #[inline]
235 pub fn reduce_mul(self) -> u8 {
236 let array: [u8x16; 2] = cast(self);
237 (array[0] * array[1]).reduce_mul()
238 }
239
240 #[inline]
241 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
242 pick! {
243 if #[cfg(target_feature="avx2")] {
244 Self {
245 avx: bitor_m256i(
246 bitand_m256i(if_one.avx, self.avx),
247 bitandnot_m256i(self.avx, if_zero.avx),
248 ),
249 }
250 } else {
251 Self {
252 a: self.a.bitselect(if_one.a, if_zero.a),
253 b: self.b.bitselect(if_one.b, if_zero.b),
254 }
255 }
256 }
257 }
258
259 #[inline]
260 fn select(self, if_true: Self, if_false: Self) -> Self {
261 pick! {
262 if #[cfg(target_feature="avx2")] {
263 Self { avx: blend_varying_i8_m256i(if_false.avx, if_true.avx, self.avx) }
264 } else {
265 Self {
266 a : self.a.select(if_true.a, if_false.a),
267 b : self.b.select(if_true.b, if_false.b),
268 }
269 }
270 }
271 }
272
273 #[inline]
274 pub fn to_bitmask(self) -> u32 {
275 pick! {
276 if #[cfg(target_feature="avx2")] {
277 move_mask_i8_m256i(self.avx) as u32
278 } else {
279 self.a.to_bitmask() | (self.b.to_bitmask() << 16)
280 }
281 }
282 }
283
284 #[inline]
285 pub fn any(self) -> bool {
286 pick! {
287 if #[cfg(target_feature="avx2")] {
288 move_mask_i8_m256i(self.avx) != 0
289 } else {
290 (self.a | self.b).any()
291 }
292 }
293 }
294
295 #[inline]
296 pub fn all(self) -> bool {
297 pick! {
298 if #[cfg(target_feature="avx2")] {
299 move_mask_i8_m256i(self.avx) == -1
300 } else {
301 (self.a & self.b).all()
302 }
303 }
304 }
305
306 #[inline]
307 pub fn shuffle(self, indices: u8x32) -> Self {
308 pick! {
309 if #[cfg(all(target_feature="avx512vbmi", target_feature="avx512vl"))] {
310 Self { avx: permute_i8_m256i(indices.avx, self.avx) }
311 } else if #[cfg(target_feature="avx2")] {
312 let tbl_lo = shuffle_abi_i128z_all_m256i::<0x00>(self.avx, self.avx);
314 let tbl_hi = shuffle_abi_i128z_all_m256i::<0x11>(self.avx, self.avx);
315 let res_lo = shuffle_av_i8z_half_m256i(tbl_lo, indices.avx);
316 let res_hi = shuffle_av_i8z_half_m256i(tbl_hi, indices.avx);
317 let sel = shl_imm_u16_m256i::<3>(indices.avx);
318 Self { avx: blend_varying_i8_m256i(res_lo, res_hi, sel) }
319 } else {
320 Self {
321 a: [self.a, self.b].shuffle(indices.a),
322 b: [self.a, self.b].shuffle(indices.b),
323 }
324 }
325 }
326 }
327
328 #[inline]
329 pub fn shuffle_zeroing(self, indices: u8x32) -> Self {
330 pick! {
331 if #[cfg(all(target_feature="avx512vbmi", target_feature="avx512vl"))] {
332 let permuted = permute_i8_m256i(indices.avx, self.avx);
335 let hi_bits = bitand_m256i(indices.avx, set_splat_i8_m256i(0xE0_u8 as i8));
336 let in_range = cmp_eq_mask_i8_m256i(hi_bits, zeroed_m256i());
337 Self { avx: bitand_m256i(permuted, in_range) }
338 } else if #[cfg(target_feature="avx2")] {
339 let idx = add_saturating_u8_m256i(indices.avx, set_splat_i8_m256i(0x60));
343 let tbl_lo = shuffle_abi_i128z_all_m256i::<0x00>(self.avx, self.avx);
344 let tbl_hi = shuffle_abi_i128z_all_m256i::<0x11>(self.avx, self.avx);
345 let res_lo = shuffle_av_i8z_half_m256i(tbl_lo, idx);
346 let res_hi = shuffle_av_i8z_half_m256i(tbl_hi, idx);
347 let sel = shl_imm_u16_m256i::<3>(indices.avx);
349 Self { avx: blend_varying_i8_m256i(res_lo, res_hi, sel) }
350 } else {
351 Self {
352 a: [self.a, self.b].shuffle_zeroing(indices.a),
353 b: [self.a, self.b].shuffle_zeroing(indices.b),
354 }
355 }
356 }
357 }
358
359 #[inline]
360 pub fn shuffle_wrapping(self, indices: u8x32) -> Self {
361 pick! {
362 if #[cfg(all(target_feature="avx512vbmi", target_feature="avx512vl"))] {
363 Self { avx: permute_i8_m256i(indices.avx, self.avx) }
364 } else if #[cfg(target_feature="avx2")] {
365 self.shuffle(indices & 31)
366 } else {
367 Self {
368 a: [self.a, self.b].shuffle_wrapping(indices.a),
369 b: [self.a, self.b].shuffle_wrapping(indices.b),
370 }
371 }
372 }
373 }
374
375 #[inline]
376 fn shuffle(self: [u8x32; 2], indices: u8x32) -> u8x32 {
377 pick! {
378 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
379 #[cfg(target_arch = "x86")]
380 use core::arch::x86::_mm256_permutex2var_epi8;
381 #[cfg(target_arch = "x86_64")]
382 use core::arch::x86_64::_mm256_permutex2var_epi8;
383 u8x32 {
385 avx: unsafe {
386 m256i(_mm256_permutex2var_epi8(self[0].avx.0, indices.avx.0, self[1].avx.0))
387 },
388 }
389 } else if #[cfg(target_feature="avx2")] {
390 self[0].shuffle_zeroing(indices) | self[1].shuffle_zeroing(indices - 32)
391 } else {
392 u8x32 {
393 a: [self[0].a, self[0].b, self[1].a, self[1].b].shuffle(indices.a),
394 b: [self[0].a, self[0].b, self[1].a, self[1].b].shuffle(indices.b),
395 }
396 }
397 }
398 }
399
400 #[inline]
401 fn shuffle_zeroing(self: [u8x32; 2], indices: u8x32) -> u8x32 {
402 pick! {
403 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
404 self.shuffle(indices) & indices.simd_lt(64)
405 } else if #[cfg(target_feature="avx2")] {
406 self.shuffle(indices)
407 } else {
408 u8x32 {
409 a: [self[0].a, self[0].b, self[1].a, self[1].b].shuffle_zeroing(indices.a),
410 b: [self[0].a, self[0].b, self[1].a, self[1].b].shuffle_zeroing(indices.b),
411 }
412 }
413 }
414 }
415
416 #[inline]
417 fn shuffle_wrapping(self: [u8x32; 2], indices: u8x32) -> u8x32 {
418 pick! {
419 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
420 self.shuffle(indices)
422 } else {
423 self.shuffle(indices & 63)
424 }
425 }
426 }
427
428 #[inline]
429 fn shuffle(self: [u8x32; 3], indices: u8x32) -> u8x32 {
430 [self[0], self[1]].shuffle_zeroing(indices) | self[2].shuffle_zeroing(indices - 64)
431 }
432
433 #[inline]
434 fn shuffle_zeroing(self: [u8x32; 3], indices: u8x32) -> u8x32 {
435 self.shuffle(indices)
436 }
437
438 #[inline]
439 fn shuffle_wrapping(self: [u8x32; 3], indices: u8x32) -> u8x32 {
440 self.shuffle(indices % 96)
441 }
442
443 #[inline]
444 fn shuffle(self: [u8x32; 4], indices: u8x32) -> u8x32 {
445 [self[0], self[1]].shuffle_zeroing(indices) | [self[2], self[3]].shuffle_zeroing(indices - 64)
446 }
447
448 #[inline]
449 fn shuffle_zeroing(self: [u8x32; 4], indices: u8x32) -> u8x32 {
450 self.shuffle(indices)
451 }
452
453 #[inline]
454 fn shuffle_wrapping(self: [u8x32; 4], indices: u8x32) -> u8x32 {
455 self.shuffle(indices & 127)
456 }
457
458 #[inline]
461 pub fn transpose(data: [Self; 32]) -> [Self; 32] {
462 #[inline(always)]
465 fn transpose_column(data: &[u8x32; 32], index: usize) -> u8x32 {
466 u8x32::new([
467 data[0].as_array()[index],
468 data[1].as_array()[index],
469 data[2].as_array()[index],
470 data[3].as_array()[index],
471 data[4].as_array()[index],
472 data[5].as_array()[index],
473 data[6].as_array()[index],
474 data[7].as_array()[index],
475 data[8].as_array()[index],
476 data[9].as_array()[index],
477 data[10].as_array()[index],
478 data[11].as_array()[index],
479 data[12].as_array()[index],
480 data[13].as_array()[index],
481 data[14].as_array()[index],
482 data[15].as_array()[index],
483 data[16].as_array()[index],
484 data[17].as_array()[index],
485 data[18].as_array()[index],
486 data[19].as_array()[index],
487 data[20].as_array()[index],
488 data[21].as_array()[index],
489 data[22].as_array()[index],
490 data[23].as_array()[index],
491 data[24].as_array()[index],
492 data[25].as_array()[index],
493 data[26].as_array()[index],
494 data[27].as_array()[index],
495 data[28].as_array()[index],
496 data[29].as_array()[index],
497 data[30].as_array()[index],
498 data[31].as_array()[index],
499 ])
500 }
501
502 [
503 transpose_column(&data, 0),
504 transpose_column(&data, 1),
505 transpose_column(&data, 2),
506 transpose_column(&data, 3),
507 transpose_column(&data, 4),
508 transpose_column(&data, 5),
509 transpose_column(&data, 6),
510 transpose_column(&data, 7),
511 transpose_column(&data, 8),
512 transpose_column(&data, 9),
513 transpose_column(&data, 10),
514 transpose_column(&data, 11),
515 transpose_column(&data, 12),
516 transpose_column(&data, 13),
517 transpose_column(&data, 14),
518 transpose_column(&data, 15),
519 transpose_column(&data, 16),
520 transpose_column(&data, 17),
521 transpose_column(&data, 18),
522 transpose_column(&data, 19),
523 transpose_column(&data, 20),
524 transpose_column(&data, 21),
525 transpose_column(&data, 22),
526 transpose_column(&data, 23),
527 transpose_column(&data, 24),
528 transpose_column(&data, 25),
529 transpose_column(&data, 26),
530 transpose_column(&data, 27),
531 transpose_column(&data, 28),
532 transpose_column(&data, 29),
533 transpose_column(&data, 30),
534 transpose_column(&data, 31),
535 ]
536 }
537
538 #[inline]
539 fn shl(self, rhs: Self) -> Self::Output {
540 pick! {
541 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
542 self.shift_each_u16(rhs.avx, false, false)
543 } else {
544 let [self_a, self_b]: [u8x16; 2] = cast(self);
545 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
546 cast([self_a << rhs_a, self_b << rhs_b])
547 }
548 }
549 }
550
551 #[inline]
552 fn shl(self, rhs: u32) -> Self::Output {
553 pick! {
554 if #[cfg(target_feature="avx2")] {
555 let values: u16x16 = cast(self);
556 let shift = rhs & 7;
557 let shifted = values << shift;
558 let crossed = u16x16::splat(!((0x00FFu16 << shift) & 0xFF00));
559 cast(shifted & crossed)
560 } else {
561 let [self_a, self_b]: [u8x16; 2] = cast(self);
562 cast([self_a << rhs, self_b << rhs])
563 }
564 }
565 }
566
567 #[inline]
568 fn shr(self, rhs: Self) -> Self::Output {
569 pick! {
570 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
571 self.shift_each_u16(rhs.avx, true, false)
572 } else {
573 let [self_a, self_b]: [u8x16; 2] = cast(self);
574 let [rhs_a, rhs_b]: [u8x16; 2] = cast(rhs);
575 cast([self_a >> rhs_a, self_b >> rhs_b])
576 }
577 }
578 }
579
580 #[inline]
581 fn shr(self, rhs: u32) -> Self::Output {
582 pick! {
583 if #[cfg(target_feature="avx2")] {
584 let values: u16x16 = cast(self);
585 let shift = rhs & 7;
586 let shifted = values >> shift;
587 let crossed = u16x16::splat(!((0xFF00u16 >> shift) & 0x00FF));
588 cast(shifted & crossed)
589 } else {
590 let [self_a, self_b]: [u8x16; 2] = cast(self);
591 cast([self_a >> rhs, self_b >> rhs])
592 }
593 }
594 }
595
596 #[inline]
597 pub fn max(self, rhs: Self) -> Self {
598 pick! {
599 if #[cfg(target_feature="avx2")] {
600 Self { avx: max_u8_m256i(self.avx,rhs.avx) }
601 } else {
602 Self {
603 a : self.a.max(rhs.a),
604 b : self.b.max(rhs.b),
605 }
606 }
607 }
608 }
609
610 #[inline]
611 pub fn min(self, rhs: Self) -> Self {
612 pick! {
613 if #[cfg(target_feature="avx2")] {
614 Self { avx: min_u8_m256i(self.avx,rhs.avx) }
615 } else {
616 Self {
617 a : self.a.min(rhs.a),
618 b : self.b.min(rhs.b),
619 }
620 }
621 }
622 }
623
624 #[inline]
625 pub fn reduce_max(self) -> u8 {
626 let array: [u8x16; 2] = cast(self);
627 array[0].max(array[1]).reduce_max()
628 }
629
630 #[inline]
631 pub fn reduce_min(self) -> u8 {
632 let array: [u8x16; 2] = cast(self);
633 array[0].min(array[1]).reduce_min()
634 }
635
636 #[inline]
637 pub fn unbounded_shl(self, rhs: Self) -> Self {
638 pick! {
639 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
640 self.shift_each_u16(rhs.avx, false, true)
641 } else {
642 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
643 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
644 cast([self_a.unbounded_shl(rhs_a), self_b.unbounded_shl(rhs_b)])
645 }
646 }
647 }
648
649 #[inline]
650 pub fn unbounded_shl_scalar(self, rhs: u32) -> Self {
651 pick! {
652 if #[cfg(target_feature="avx2")] {
653 let values: u16x16 = cast(self);
654 let shifted = values.unbounded_shl_scalar(rhs);
655 let crossed = u16x16::splat(!(0x00FFu16.wrapping_shl(rhs) & 0xFF00));
656 cast(shifted & crossed)
657 } else {
658 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
659 cast([self_a.unbounded_shl_scalar(rhs), self_b.unbounded_shl_scalar(rhs)])
660 }
661 }
662 }
663
664 #[inline]
665 pub fn unbounded_shr(self, rhs: Self) -> Self {
666 pick! {
667 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
668 self.shift_each_u16(rhs.avx, true, true)
669 } else {
670 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
671 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
672 cast([self_a.unbounded_shr(rhs_a), self_b.unbounded_shr(rhs_b)])
673 }
674 }
675 }
676
677 #[inline]
678 pub fn unbounded_shr_scalar(self, rhs: u32) -> Self {
679 pick! {
680 if #[cfg(target_feature="avx2")] {
681 let values: u16x16 = cast(self);
682 let shifted = values.unbounded_shr_scalar(rhs);
683 let crossed = u16x16::splat(!(0xFF00u16.wrapping_shr(rhs) & 0x00FF));
684 cast(shifted & crossed)
685 } else {
686 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
687 cast([self_a.unbounded_shr_scalar(rhs), self_b.unbounded_shr_scalar(rhs)])
688 }
689 }
690 }
691
692 #[inline]
693 pub fn saturating_add(self, rhs: Self) -> Self {
694 pick! {
695 if #[cfg(target_feature="avx2")] {
696 Self { avx: add_saturating_u8_m256i(self.avx, rhs.avx) }
697 } else {
698 Self {
699 a : self.a.saturating_add(rhs.a),
700 b : self.b.saturating_add(rhs.b),
701 }
702 }
703 }
704 }
705
706 #[inline]
707 pub fn saturating_sub(self, rhs: Self) -> Self {
708 pick! {
709 if #[cfg(target_feature="avx2")] {
710 Self { avx: sub_saturating_u8_m256i(self.avx, rhs.avx) }
711 } else {
712 Self {
713 a : self.a.saturating_sub(rhs.a),
714 b : self.b.saturating_sub(rhs.b),
715 }
716 }
717 }
718 }
719
720 #[inline]
721 pub fn overflowing_mul(self, rhs: Self) -> (Self, Self) {
722 let (low, high) = self.mul_keep_low_high(rhs);
723 let overflow = high.simd_ne(Self::ZERO);
724 (low, overflow)
725 }
726
727 optional_fn_widening_mul {
728 #[inline]
729 pub fn widening_mul(self, rhs: Self) -> u16x32 {
730 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
734 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
735
736 cast([self_a.widening_mul(rhs_a), self_b.widening_mul(rhs_b)])
737 }
738 }
739
740 #[inline]
741 pub fn mul_keep_low_high(self, rhs: Self) -> (Self, Self) {
742 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
746 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
747
748 let result_a = self_a.mul_keep_low_high(rhs_a);
749 let result_b = self_b.mul_keep_low_high(rhs_b);
750 (cast([result_a.0, result_b.0]), cast([result_a.1, result_b.1]))
751 }
752
753 #[inline]
754 pub fn mul_keep_high(self, rhs: Self) -> Self {
755 let [self_a, self_b] = cast::<u8x32, [u8x16; 2]>(self);
759 let [rhs_a, rhs_b] = cast::<u8x32, [u8x16; 2]>(rhs);
760
761 cast([self_a.mul_keep_high(rhs_a), self_b.mul_keep_high(rhs_b)])
762 }
763
764 optional_fn_deserialize {}
765}
766
767impl u8x32 {
770 #[inline]
779 pub fn swizzle_half(self, rhs: i8x32) -> i8x32 {
780 cast(i8x32::swizzle_half(cast(self), cast(rhs)))
781 }
782
783 #[inline]
793 pub fn swizzle_half_relaxed(self, rhs: u8x32) -> u8x32 {
794 cast(i8x32::swizzle_half_relaxed(cast(self), cast(rhs)))
795 }
796
797 #[inline]
804 #[deprecated(since = "1.7.0", note = "replaced with `shuffle_zeroing`")]
805 pub fn swizzle(self, rhs: u8x32) -> u8x32 {
806 self.shuffle_zeroing(rhs)
807 }
808
809 #[inline]
816 #[deprecated(since = "1.7.0", note = "replaced with `shuffle`")]
817 pub fn swizzle_relaxed(self, rhs: u8x32) -> u8x32 {
818 self.shuffle(rhs)
819 }
820}
821
822#[cfg(target_feature = "avx2")]
823impl u8x32 {
824 #[cfg(all(target_feature = "avx512bw", target_feature = "avx512vl"))]
831 #[inline]
832 fn shift_each_u16(self, rhs: m256i, right: bool, unbounded: bool) -> Self {
833 let self16 = convert_to_i16_m512i_from_u8_m256i(self.avx);
834 let count16 = if unbounded {
835 convert_to_u16_m512i_from_u8_m256i(min_u8_m256i(
836 rhs,
837 set_splat_i8_m256i(8),
838 ))
839 } else {
840 bitand_m512i(
841 convert_to_u16_m512i_from_u8_m256i(rhs),
842 set_splat_i16_m512i(7),
843 )
844 };
845 let shifted = if right {
846 shr_each_u16_m512i(self16, count16)
847 } else {
848 shl_each_u16_m512i(self16, count16)
849 };
850 let shifted = bitand_m512i(shifted, set_splat_i16_m512i(0xFF));
851 Self {
852 avx: Self::pack_u16_halves(
853 extract_m256i_from_m512i::<0>(shifted),
854 extract_m256i_from_m512i::<1>(shifted),
855 ),
856 }
857 }
858
859 #[cfg(all(target_feature = "avx512bw", target_feature = "avx512vl"))]
863 #[inline]
864 fn pack_u16_halves(low: m256i, high: m256i) -> m256i {
865 let packed = pack_i16_to_u8_m256i(low, high);
866 let packed_low = extract_m128i_m256i::<0>(packed);
867 let packed_high = extract_m128i_m256i::<1>(packed);
868 let combined_low = unpack_low_i64_m128i(packed_low, packed_high);
869 let combined_high = unpack_high_i64_m128i(packed_low, packed_high);
870 insert_m128i_to_m256i::<1>(
871 insert_m128i_to_m256i::<0>(zeroed_m256i(), combined_low),
872 combined_high,
873 )
874 }
875}