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