1use super::*;
2
3pick! {
4 if #[cfg(target_feature="avx2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
6 #[repr(C, align(32))]
7 pub struct i8x32 { avx: m256i }
8 } else {
9 #[derive(Default, Clone, Copy, PartialEq, Eq)]
10 #[repr(C, align(32))]
11 pub struct i8x32 { a : i8x16, b : i8x16 }
12 }
13}
14
15int_uint_consts!(i8, 32, i8x32, 256);
16
17unsafe impl Zeroable for i8x32 {}
18unsafe impl Pod for i8x32 {}
19
20impl AlignTo for i8x32 {
21 type Elem = i8;
22}
23
24impl Add for i8x32 {
25 type Output = Self;
26 #[inline]
27 fn add(self, rhs: Self) -> Self::Output {
28 pick! {
29 if #[cfg(target_feature="avx2")] {
30 Self { avx: add_i8_m256i(self.avx,rhs.avx) }
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 i8x32 {
42 type Output = Self;
43 #[inline]
44 fn sub(self, rhs: Self) -> Self::Output {
45 pick! {
46 if #[cfg(target_feature="avx2")] {
47 Self { avx: sub_i8_m256i(self.avx,rhs.avx) }
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 i8x32 {
59 type Output = Self;
60
61 #[inline]
62 fn mul(self, rhs: Self) -> Self::Output {
63 let [self_a, self_b]: [i8x16; 2] = cast(self);
67 let [rhs_a, rhs_b]: [i8x16; 2] = cast(rhs);
68 cast([self_a * rhs_a, self_b * rhs_b])
69 }
70}
71
72integer_impl_div_rem!(
73 i8,
74 i8x32,
75 [
76 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
77 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
78 ],
79);
80
81impl Shl for i8x32 {
82 type Output = Self;
83
84 #[inline]
85 fn shl(self, rhs: Self) -> Self::Output {
86 let [self_a, self_b]: [i8x16; 2] = cast(self);
90 let [rhs_a, rhs_b]: [i8x16; 2] = cast(rhs);
91 cast([self_a << rhs_a, self_b << rhs_b])
92 }
93}
94
95impl Shr for i8x32 {
96 type Output = Self;
97
98 #[inline]
99 fn shr(self, rhs: Self) -> Self::Output {
100 let [self_a, self_b]: [i8x16; 2] = cast(self);
104 let [rhs_a, rhs_b]: [i8x16; 2] = cast(rhs);
105 cast([self_a >> rhs_a, self_b >> rhs_b])
106 }
107}
108
109impl Add<i8> for i8x32 {
110 type Output = Self;
111 #[inline]
112 fn add(self, rhs: i8) -> Self::Output {
113 self.add(Self::splat(rhs))
114 }
115}
116
117impl Sub<i8> for i8x32 {
118 type Output = Self;
119 #[inline]
120 fn sub(self, rhs: i8) -> Self::Output {
121 self.sub(Self::splat(rhs))
122 }
123}
124
125impl Mul<i8> for i8x32 {
126 type Output = Self;
127
128 #[inline]
129 fn mul(self, rhs: i8) -> Self::Output {
130 self * Self::splat(rhs)
131 }
132}
133
134macro_rules! impl_shl_scalar {
135 ($Rhs:ident) => {
136 impl Shl<$Rhs> for i8x32 {
137 type Output = Self;
138
139 #[inline]
141 fn shl(self, rhs: $Rhs) -> Self::Output {
142 let [self_a, self_b]: [i8x16; 2] = cast(self);
146 cast([self_a << rhs, self_b << rhs])
147 }
148 }
149 };
150}
151impl_shl_scalar!(i8);
152impl_shl_scalar!(u8);
153impl_shl_scalar!(i16);
154impl_shl_scalar!(u16);
155impl_shl_scalar!(i32);
156impl_shl_scalar!(u32);
157impl_shl_scalar!(i64);
158impl_shl_scalar!(u64);
159impl_shl_scalar!(i128);
160impl_shl_scalar!(u128);
161
162macro_rules! impl_shr_scalar {
163 ($Rhs:ident) => {
164 impl Shr<$Rhs> for i8x32 {
165 type Output = Self;
166
167 #[inline]
169 fn shr(self, rhs: $Rhs) -> Self::Output {
170 let [self_a, self_b]: [i8x16; 2] = cast(self);
174 cast([self_a >> rhs, self_b >> rhs])
175 }
176 }
177 };
178}
179impl_shr_scalar!(i8);
180impl_shr_scalar!(u8);
181impl_shr_scalar!(i16);
182impl_shr_scalar!(u16);
183impl_shr_scalar!(i32);
184impl_shr_scalar!(u32);
185impl_shr_scalar!(i64);
186impl_shr_scalar!(u64);
187impl_shr_scalar!(i128);
188impl_shr_scalar!(u128);
189
190impl Add<i8x32> for i8 {
191 type Output = i8x32;
192 #[inline]
193 fn add(self, rhs: i8x32) -> Self::Output {
194 i8x32::splat(self).add(rhs)
195 }
196}
197
198impl Sub<i8x32> for i8 {
199 type Output = i8x32;
200 #[inline]
201 fn sub(self, rhs: i8x32) -> Self::Output {
202 i8x32::splat(self).sub(rhs)
203 }
204}
205
206impl Mul<i8x32> for i8 {
207 type Output = i8x32;
208
209 #[inline]
210 fn mul(self, rhs: i8x32) -> Self::Output {
211 i8x32::splat(self) * rhs
212 }
213}
214
215impl BitAnd for i8x32 {
216 type Output = Self;
217 #[inline]
218 fn bitand(self, rhs: Self) -> Self::Output {
219 pick! {
220 if #[cfg(target_feature="avx2")] {
221 Self { avx : bitand_m256i(self.avx,rhs.avx) }
222 } else {
223 Self {
224 a : self.a.bitand(rhs.a),
225 b : self.b.bitand(rhs.b),
226 }
227 }
228 }
229 }
230}
231
232impl BitOr for i8x32 {
233 type Output = Self;
234 #[inline]
235 fn bitor(self, rhs: Self) -> Self::Output {
236 pick! {
237 if #[cfg(target_feature="avx2")] {
238 Self { avx : bitor_m256i(self.avx,rhs.avx) }
239 } else {
240 Self {
241 a : self.a.bitor(rhs.a),
242 b : self.b.bitor(rhs.b),
243 }
244 }
245 }
246 }
247}
248
249impl BitXor for i8x32 {
250 type Output = Self;
251 #[inline]
252 fn bitxor(self, rhs: Self) -> Self::Output {
253 pick! {
254 if #[cfg(target_feature="avx2")] {
255 Self { avx : bitxor_m256i(self.avx,rhs.avx) }
256 } else {
257 Self {
258 a : self.a.bitxor(rhs.a),
259 b : self.b.bitxor(rhs.b),
260 }
261 }
262 }
263 }
264}
265
266#[expect(deprecated)]
267impl CmpEq for i8x32 {
268 type Output = Self;
269 #[inline]
270 fn simd_eq(self, rhs: Self) -> Self::Output {
271 pick! {
272 if #[cfg(target_feature="avx2")] {
273 Self { avx : cmp_eq_mask_i8_m256i(self.avx,rhs.avx) }
274 } else {
275 Self {
276 a : self.a.simd_eq(rhs.a),
277 b : self.b.simd_eq(rhs.b),
278 }
279 }
280 }
281 }
282}
283
284#[expect(deprecated)]
285impl CmpGt for i8x32 {
286 type Output = Self;
287 #[inline]
288 fn simd_gt(self, rhs: Self) -> Self::Output {
289 pick! {
290 if #[cfg(target_feature="avx2")] {
291 Self { avx : cmp_gt_mask_i8_m256i(self.avx,rhs.avx) }
292 } else {
293 Self {
294 a : self.a.simd_gt(rhs.a),
295 b : self.b.simd_gt(rhs.b),
296 }
297 }
298 }
299 }
300}
301
302#[expect(deprecated)]
303impl CmpLt for i8x32 {
304 type Output = Self;
305 #[inline]
306 fn simd_lt(self, rhs: Self) -> Self::Output {
307 rhs.simd_gt(self)
308 }
309}
310
311#[expect(deprecated)]
312impl CmpNe for i8x32 {
313 type Output = Self;
314 #[inline]
315 fn simd_ne(self, rhs: Self) -> Self::Output {
316 pick! {
317 if #[cfg(target_feature="avx2")] {
318 !self.simd_eq(rhs)
319 } else {
320 Self {
321 a : self.a.simd_ne(rhs.a),
322 b : self.b.simd_ne(rhs.b),
323 }
324 }
325 }
326 }
327}
328
329#[expect(deprecated)]
330impl CmpLe for i8x32 {
331 type Output = Self;
332 #[inline]
333 fn simd_le(self, rhs: Self) -> Self::Output {
334 pick! {
335 if #[cfg(target_feature="avx2")] {
336 !self.simd_gt(rhs)
337 } else {
338 Self {
339 a : self.a.simd_le(rhs.a),
340 b : self.b.simd_le(rhs.b),
341 }
342 }
343 }
344 }
345}
346
347#[expect(deprecated)]
348impl CmpGe for i8x32 {
349 type Output = Self;
350 #[inline]
351 fn simd_ge(self, rhs: Self) -> Self::Output {
352 pick! {
353 if #[cfg(target_feature="avx2")] {
354 !self.simd_lt(rhs)
355 } else {
356 Self {
357 a : self.a.simd_ge(rhs.a),
358 b : self.b.simd_ge(rhs.b),
359 }
360 }
361 }
362 }
363}
364
365impl Not for i8x32 {
366 type Output = Self;
367 #[inline]
368 fn not(self) -> Self {
369 pick! {
370 if #[cfg(target_feature="avx2")] {
371 Self { avx: self.avx.not() }
372 } else {
373 Self {
374 a : self.a.not(),
375 b : self.b.not(),
376 }
377 }
378 }
379 }
380}
381
382impl i8x32 {
383 #[inline]
384 #[must_use]
385 pub const fn new(array: [i8; 32]) -> Self {
386 unsafe { core::mem::transmute(array) }
387 }
388
389 simd_comparison_fns!();
390
391 #[inline]
392 #[must_use]
393 pub fn blend(self, t: Self, f: Self) -> Self {
394 pick! {
395 if #[cfg(target_feature="avx2")] {
396 Self { avx: blend_varying_i8_m256i(f.avx, t.avx, self.avx) }
397 } else {
398 Self {
399 a : self.a.blend(t.a, f.a),
400 b : self.b.blend(t.b, f.b),
401 }
402 }
403 }
404 }
405
406 #[inline]
409 #[must_use]
410 pub fn is_positive(self) -> Self {
411 pick! {
412 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
413 Self {
415 a: self.a.is_positive(),
416 b: self.b.is_positive(),
417 }
418 } else {
419 self.simd_gt(Self::ZERO)
420 }
421 }
422 }
423
424 #[inline]
427 #[must_use]
428 pub fn is_negative(self) -> Self {
429 pick! {
430 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
431 Self {
433 a: self.a.is_negative(),
434 b: self.b.is_negative(),
435 }
436 } else {
437 self.simd_lt(Self::ZERO)
438 }
439 }
440 }
441
442 #[inline]
443 #[must_use]
444 pub fn reduce_add(self) -> i8 {
445 let array: [i8x16; 2] = cast(self);
446 (array[0] + array[1]).reduce_add()
447 }
448
449 #[inline]
450 #[must_use]
451 pub fn reduce_max(self) -> i8 {
452 let array: [i8x16; 2] = cast(self);
453 array[0].max(array[1]).reduce_max()
454 }
455
456 #[inline]
457 #[must_use]
458 pub fn reduce_min(self) -> i8 {
459 let array: [i8x16; 2] = cast(self);
460 array[0].min(array[1]).reduce_min()
461 }
462
463 #[inline]
464 #[must_use]
465 pub fn abs(self) -> Self {
466 pick! {
467 if #[cfg(target_feature="avx2")] {
468 Self { avx: abs_i8_m256i(self.avx) }
469 } else {
470 Self {
471 a : self.a.abs(),
472 b : self.b.abs(),
473 }
474 }
475 }
476 }
477
478 #[inline]
479 #[must_use]
480 pub fn unsigned_abs(self) -> u8x32 {
481 pick! {
482 if #[cfg(target_feature="avx2")] {
483 u8x32 { avx: abs_i8_m256i(self.avx) }
484 } else {
485 u8x32 {
486 a : self.a.unsigned_abs(),
487 b : self.b.unsigned_abs(),
488 }
489 }
490 }
491 }
492
493 signed_fn_signum!();
494
495 #[inline]
496 #[must_use]
497 pub fn max(self, rhs: Self) -> Self {
498 pick! {
499 if #[cfg(target_feature="avx2")] {
500 Self { avx: max_i8_m256i(self.avx,rhs.avx) }
501 } else {
502 Self {
503 a : self.a.max(rhs.a),
504 b : self.b.max(rhs.b),
505 }
506 }
507 }
508 }
509 #[inline]
510 #[must_use]
511 pub fn min(self, rhs: Self) -> Self {
512 pick! {
513 if #[cfg(target_feature="avx2")] {
514 Self { avx: min_i8_m256i(self.avx,rhs.avx) }
515 } else {
516 Self {
517 a : self.a.min(rhs.a),
518 b : self.b.min(rhs.b),
519 }
520 }
521 }
522 }
523
524 integer_fn_clamp!();
525
526 #[inline]
527 #[must_use]
528 pub fn saturating_add(self, rhs: Self) -> Self {
529 pick! {
530 if #[cfg(target_feature="avx2")] {
531 Self { avx: add_saturating_i8_m256i(self.avx, rhs.avx) }
532 } else {
533 Self {
534 a : self.a.saturating_add(rhs.a),
535 b : self.b.saturating_add(rhs.b),
536 }
537 }
538 }
539 }
540 #[inline]
541 #[must_use]
542 pub fn saturating_sub(self, rhs: Self) -> Self {
543 pick! {
544 if #[cfg(target_feature="avx2")] {
545 Self { avx: sub_saturating_i8_m256i(self.avx, rhs.avx) }
546 } else {
547 Self {
548 a : self.a.saturating_sub(rhs.a),
549 b : self.b.saturating_sub(rhs.b),
550 }
551 }
552 }
553 }
554
555 #[inline]
557 #[must_use]
558 pub fn saturating_mul(self, rhs: Self) -> Self {
559 let [self_a, self_b]: [i8x16; 2] = cast(self);
560 let [rhs_a, rhs_b]: [i8x16; 2] = cast(rhs);
561 cast([self_a.saturating_mul(rhs_a), self_b.saturating_mul(rhs_b)])
562 }
563
564 integer_fn_saturating_div!([
565 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
566 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
567 ]);
568
569 #[inline]
570 #[must_use]
571 #[doc(alias("movemask", "move_mask"))]
572 pub fn to_bitmask(self) -> u32 {
573 pick! {
574 if #[cfg(target_feature="avx2")] {
575 move_mask_i8_m256i(self.avx) as u32
576 } else {
577 self.a.to_bitmask() | (self.b.to_bitmask() << 16)
578 }
579 }
580 }
581
582 #[inline]
583 #[must_use]
584 pub fn any(self) -> bool {
585 pick! {
586 if #[cfg(target_feature="avx2")] {
587 move_mask_i8_m256i(self.avx) != 0
588 } else {
589 (self.a | self.b).any()
590 }
591 }
592 }
593
594 #[inline]
595 #[must_use]
596 pub fn all(self) -> bool {
597 pick! {
598 if #[cfg(target_feature="avx2")] {
599 move_mask_i8_m256i(self.avx) == -1
600 } else {
601 (self.a & self.b).all()
602 }
603 }
604 }
605
606 #[inline]
607 #[must_use]
608 pub fn none(self) -> bool {
609 !self.any()
610 }
611
612 #[inline]
621 pub fn swizzle_half(self, rhs: i8x32) -> i8x32 {
622 pick! {
623 if #[cfg(target_feature="avx2")] {
624 Self { avx: shuffle_av_i8z_half_m256i(self.avx, rhs.saturating_add(i8x32::splat(0x60)).avx) }
625 } else {
626 Self {
627 a : self.a.swizzle(rhs.a),
628 b : self.b.swizzle(rhs.b),
629 }
630 }
631 }
632 }
633
634 #[inline]
644 pub fn swizzle_half_relaxed(self, rhs: i8x32) -> i8x32 {
645 pick! {
646 if #[cfg(target_feature="avx2")] {
647 Self { avx: shuffle_av_i8z_half_m256i(self.avx, rhs.avx) }
648 } else {
649 Self {
650 a : self.a.swizzle_relaxed(rhs.a),
651 b : self.b.swizzle_relaxed(rhs.b),
652 }
653 }
654 }
655 }
656
657 #[must_use]
659 #[inline]
660 pub fn transpose(data: [i8x32; 32]) -> [i8x32; 32] {
661 #[inline(always)]
664 fn transpose_column(data: &[i8x32; 32], index: usize) -> i8x32 {
665 i8x32::new([
666 data[0].as_array()[index],
667 data[1].as_array()[index],
668 data[2].as_array()[index],
669 data[3].as_array()[index],
670 data[4].as_array()[index],
671 data[5].as_array()[index],
672 data[6].as_array()[index],
673 data[7].as_array()[index],
674 data[8].as_array()[index],
675 data[9].as_array()[index],
676 data[10].as_array()[index],
677 data[11].as_array()[index],
678 data[12].as_array()[index],
679 data[13].as_array()[index],
680 data[14].as_array()[index],
681 data[15].as_array()[index],
682 data[16].as_array()[index],
683 data[17].as_array()[index],
684 data[18].as_array()[index],
685 data[19].as_array()[index],
686 data[20].as_array()[index],
687 data[21].as_array()[index],
688 data[22].as_array()[index],
689 data[23].as_array()[index],
690 data[24].as_array()[index],
691 data[25].as_array()[index],
692 data[26].as_array()[index],
693 data[27].as_array()[index],
694 data[28].as_array()[index],
695 data[29].as_array()[index],
696 data[30].as_array()[index],
697 data[31].as_array()[index],
698 ])
699 }
700
701 [
702 transpose_column(&data, 0),
703 transpose_column(&data, 1),
704 transpose_column(&data, 2),
705 transpose_column(&data, 3),
706 transpose_column(&data, 4),
707 transpose_column(&data, 5),
708 transpose_column(&data, 6),
709 transpose_column(&data, 7),
710 transpose_column(&data, 8),
711 transpose_column(&data, 9),
712 transpose_column(&data, 10),
713 transpose_column(&data, 11),
714 transpose_column(&data, 12),
715 transpose_column(&data, 13),
716 transpose_column(&data, 14),
717 transpose_column(&data, 15),
718 transpose_column(&data, 16),
719 transpose_column(&data, 17),
720 transpose_column(&data, 18),
721 transpose_column(&data, 19),
722 transpose_column(&data, 20),
723 transpose_column(&data, 21),
724 transpose_column(&data, 22),
725 transpose_column(&data, 23),
726 transpose_column(&data, 24),
727 transpose_column(&data, 25),
728 transpose_column(&data, 26),
729 transpose_column(&data, 27),
730 transpose_column(&data, 28),
731 transpose_column(&data, 29),
732 transpose_column(&data, 30),
733 transpose_column(&data, 31),
734 ]
735 }
736
737 #[inline]
738 pub fn to_array(self) -> [i8; 32] {
739 cast(self)
740 }
741
742 #[inline]
743 pub fn as_array(&self) -> &[i8; 32] {
744 cast_ref(self)
745 }
746
747 #[inline]
748 pub fn as_mut_array(&mut self) -> &mut [i8; 32] {
749 cast_mut(self)
750 }
751}