1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
6 #[repr(C, align(16))]
7 pub struct i32x4 { pub(crate) sse: m128i }
8 } else if #[cfg(target_feature="simd128")] {
9 use core::arch::wasm32::*;
10
11 #[derive(Clone, Copy)]
12 #[repr(transparent)]
13 pub struct i32x4 { pub(crate) simd: v128 }
14
15 impl Default for i32x4 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for i32x4 {
22 fn eq(&self, other: &Self) -> bool {
23 u32x4_all_true(i32x4_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for i32x4 { }
28 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
29 use core::arch::aarch64::*;
30 #[repr(C)]
31 #[derive(Copy, Clone)]
32 pub struct i32x4 { pub(crate) neon : int32x4_t }
33
34 impl Default for i32x4 {
35 #[inline]
36 fn default() -> Self {
37 Self::splat(0)
38 }
39 }
40
41 impl PartialEq for i32x4 {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 unsafe { vminvq_u32(vceqq_s32(self.neon, other.neon))==u32::MAX }
45 }
46 }
47
48 impl Eq for i32x4 { }
49 } else {
50 #[derive(Default, Clone, Copy, PartialEq, Eq)]
51 #[repr(C, align(16))]
52 pub struct i32x4 { pub(crate) arr: [i32;4] }
53 }
54}
55
56int_uint_consts!(i32, 4, i32x4, 128);
57
58unsafe impl Zeroable for i32x4 {}
59unsafe impl Pod for i32x4 {}
60
61impl AlignTo for i32x4 {
62 type Elem = i32;
63}
64
65impl Add for i32x4 {
66 type Output = Self;
67 #[inline]
68 fn add(self, rhs: Self) -> Self::Output {
69 pick! {
70 if #[cfg(target_feature="sse2")] {
71 Self { sse: add_i32_m128i(self.sse, rhs.sse) }
72 } else if #[cfg(target_feature="simd128")] {
73 Self { simd: i32x4_add(self.simd, rhs.simd) }
74 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
75 unsafe { Self { neon: vaddq_s32(self.neon, rhs.neon) } }
76 } else {
77 Self { arr: [
78 self.arr[0].wrapping_add(rhs.arr[0]),
79 self.arr[1].wrapping_add(rhs.arr[1]),
80 self.arr[2].wrapping_add(rhs.arr[2]),
81 self.arr[3].wrapping_add(rhs.arr[3]),
82 ]}
83 }
84 }
85 }
86}
87
88impl Sub for i32x4 {
89 type Output = Self;
90 #[inline]
91 fn sub(self, rhs: Self) -> Self::Output {
92 pick! {
93 if #[cfg(target_feature="sse2")] {
94 Self { sse: sub_i32_m128i(self.sse, rhs.sse) }
95 } else if #[cfg(target_feature="simd128")] {
96 Self { simd: i32x4_sub(self.simd, rhs.simd) }
97 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
98 unsafe {Self { neon: vsubq_s32(self.neon, rhs.neon) }}
99 } else {
100 Self { arr: [
101 self.arr[0].wrapping_sub(rhs.arr[0]),
102 self.arr[1].wrapping_sub(rhs.arr[1]),
103 self.arr[2].wrapping_sub(rhs.arr[2]),
104 self.arr[3].wrapping_sub(rhs.arr[3]),
105 ]}
106 }
107 }
108 }
109}
110
111impl Mul for i32x4 {
112 type Output = Self;
113 #[inline]
114 fn mul(self, rhs: Self) -> Self::Output {
115 pick! {
116 if #[cfg(target_feature="sse4.1")] {
117 Self { sse: mul_32_m128i(self.sse, rhs.sse) }
118 } else if #[cfg(target_feature="simd128")] {
119 Self { simd: i32x4_mul(self.simd, rhs.simd) }
120 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
121 unsafe {Self { neon: vmulq_s32(self.neon, rhs.neon) }}
122 } else {
123 let arr1: [i32; 4] = cast(self);
124 let arr2: [i32; 4] = cast(rhs);
125 cast([
126 arr1[0].wrapping_mul(arr2[0]),
127 arr1[1].wrapping_mul(arr2[1]),
128 arr1[2].wrapping_mul(arr2[2]),
129 arr1[3].wrapping_mul(arr2[3]),
130 ])
131 }
132 }
133 }
134}
135
136integer_impl_div_rem!(i32, i32x4, [0, 1, 2, 3]);
137
138impl Add<i32> for i32x4 {
139 type Output = Self;
140 #[inline]
141 fn add(self, rhs: i32) -> Self::Output {
142 self.add(Self::splat(rhs))
143 }
144}
145
146impl Sub<i32> for i32x4 {
147 type Output = Self;
148 #[inline]
149 fn sub(self, rhs: i32) -> Self::Output {
150 self.sub(Self::splat(rhs))
151 }
152}
153
154impl Mul<i32> for i32x4 {
155 type Output = Self;
156 #[inline]
157 fn mul(self, rhs: i32) -> Self::Output {
158 self.mul(Self::splat(rhs))
159 }
160}
161
162impl Add<i32x4> for i32 {
163 type Output = i32x4;
164 #[inline]
165 fn add(self, rhs: i32x4) -> Self::Output {
166 i32x4::splat(self).add(rhs)
167 }
168}
169
170impl Sub<i32x4> for i32 {
171 type Output = i32x4;
172 #[inline]
173 fn sub(self, rhs: i32x4) -> Self::Output {
174 i32x4::splat(self).sub(rhs)
175 }
176}
177
178impl Mul<i32x4> for i32 {
179 type Output = i32x4;
180 #[inline]
181 fn mul(self, rhs: i32x4) -> Self::Output {
182 i32x4::splat(self).mul(rhs)
183 }
184}
185
186impl BitAnd for i32x4 {
187 type Output = Self;
188 #[inline]
189 fn bitand(self, rhs: Self) -> Self::Output {
190 pick! {
191 if #[cfg(target_feature="sse2")] {
192 Self { sse: bitand_m128i(self.sse, rhs.sse) }
193 } else if #[cfg(target_feature="simd128")] {
194 Self { simd: v128_and(self.simd, rhs.simd) }
195 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
196 unsafe {Self { neon: vandq_s32(self.neon, rhs.neon) }}
197 } else {
198 Self { arr: [
199 self.arr[0].bitand(rhs.arr[0]),
200 self.arr[1].bitand(rhs.arr[1]),
201 self.arr[2].bitand(rhs.arr[2]),
202 self.arr[3].bitand(rhs.arr[3]),
203 ]}
204 }
205 }
206 }
207}
208
209impl BitOr for i32x4 {
210 type Output = Self;
211 #[inline]
212 fn bitor(self, rhs: Self) -> Self::Output {
213 pick! {
214 if #[cfg(target_feature="sse2")] {
215 Self { sse: bitor_m128i(self.sse, rhs.sse) }
216 } else if #[cfg(target_feature="simd128")] {
217 Self { simd: v128_or(self.simd, rhs.simd) }
218 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
219 unsafe {Self { neon: vorrq_s32(self.neon, rhs.neon) }}
220 } else {
221 Self { arr: [
222 self.arr[0].bitor(rhs.arr[0]),
223 self.arr[1].bitor(rhs.arr[1]),
224 self.arr[2].bitor(rhs.arr[2]),
225 self.arr[3].bitor(rhs.arr[3]),
226 ]}
227 }
228 }
229 }
230}
231
232impl BitXor for i32x4 {
233 type Output = Self;
234 #[inline]
235 fn bitxor(self, rhs: Self) -> Self::Output {
236 pick! {
237 if #[cfg(target_feature="sse2")] {
238 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
239 } else if #[cfg(target_feature="simd128")] {
240 Self { simd: v128_xor(self.simd, rhs.simd) }
241 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
242 unsafe {Self { neon: veorq_s32(self.neon, rhs.neon) }}
243 } else {
244 Self { arr: [
245 self.arr[0].bitxor(rhs.arr[0]),
246 self.arr[1].bitxor(rhs.arr[1]),
247 self.arr[2].bitxor(rhs.arr[2]),
248 self.arr[3].bitxor(rhs.arr[3]),
249 ]}
250 }
251 }
252 }
253}
254
255macro_rules! impl_shl_t_for_i32x4 {
256 ($($shift_type:ty),+ $(,)?) => {
257 $(impl Shl<$shift_type> for i32x4 {
258 type Output = Self;
259 #[inline]
261 fn shl(self, rhs: $shift_type) -> Self::Output {
262 pick! {
263 if #[cfg(target_feature="sse2")] {
264 let shift = cast([rhs as u64, 0]);
265 Self { sse: shl_all_u32_m128i(self.sse, shift) }
266 } else if #[cfg(target_feature="simd128")] {
267 Self { simd: i32x4_shl(self.simd, rhs as u32) }
268 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
269 unsafe {Self { neon: vshlq_s32(self.neon, vmovq_n_s32(rhs as i32)) }}
270 } else {
271 let u = rhs as u32;
272 Self { arr: [
273 self.arr[0].wrapping_shl(u),
274 self.arr[1].wrapping_shl(u),
275 self.arr[2].wrapping_shl(u),
276 self.arr[3].wrapping_shl(u),
277 ]}
278 }
279 }
280 }
281 })+
282 };
283}
284impl_shl_t_for_i32x4!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
285
286macro_rules! impl_shr_t_for_i32x4 {
287 ($($shift_type:ty),+ $(,)?) => {
288 $(impl Shr<$shift_type> for i32x4 {
289 type Output = Self;
290 #[inline]
292 fn shr(self, rhs: $shift_type) -> Self::Output {
293 pick! {
294 if #[cfg(target_feature="sse2")] {
295 let shift = cast([rhs as u64, 0]);
296 Self { sse: shr_all_i32_m128i(self.sse, shift) }
297 } else if #[cfg(target_feature="simd128")] {
298 Self { simd: i32x4_shr(self.simd, rhs as u32) }
299 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
300 unsafe {Self { neon: vshlq_s32(self.neon, vmovq_n_s32( -(rhs as i32))) }}
301 } else {
302 let u = rhs as u32;
303 Self { arr: [
304 self.arr[0].wrapping_shr(u),
305 self.arr[1].wrapping_shr(u),
306 self.arr[2].wrapping_shr(u),
307 self.arr[3].wrapping_shr(u),
308 ]}
309 }
310 }
311 }
312 })+
313 };
314}
315impl_shr_t_for_i32x4!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
316
317impl Shr<i32x4> for i32x4 {
323 type Output = Self;
324
325 #[inline]
326 fn shr(self, rhs: i32x4) -> Self::Output {
327 pick! {
328 if #[cfg(target_feature="avx2")] {
329 let shift_by = bitand_m128i(rhs.sse, set_splat_i32_m128i(31));
331 Self { sse: shr_each_i32_m128i(self.sse, shift_by) }
332 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
333 unsafe {
334 let shift_by = vnegq_s32(vandq_s32(rhs.neon, vmovq_n_s32(31)));
337 Self { neon: vshlq_s32(self.neon, shift_by) }
338 }
339 } else {
340 let arr: [i32; 4] = cast(self);
341 let rhs: [i32; 4] = cast(rhs);
342 cast([
343 arr[0].wrapping_shr(rhs[0] as u32),
344 arr[1].wrapping_shr(rhs[1] as u32),
345 arr[2].wrapping_shr(rhs[2] as u32),
346 arr[3].wrapping_shr(rhs[3] as u32),
347 ])
348 }
349 }
350 }
351}
352
353impl Shl<i32x4> for i32x4 {
359 type Output = Self;
360
361 #[inline]
362 fn shl(self, rhs: i32x4) -> Self::Output {
363 pick! {
364 if #[cfg(target_feature="avx2")] {
365 let shift_by = bitand_m128i(rhs.sse, set_splat_i32_m128i(31));
367 Self { sse: shl_each_u32_m128i(self.sse, shift_by) }
368 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
369 unsafe {
370 let shift_by = vandq_s32(rhs.neon, vmovq_n_s32(31));
372 Self { neon: vshlq_s32(self.neon, shift_by) }
373 }
374 } else {
375 let arr: [i32; 4] = cast(self);
376 let rhs: [i32; 4] = cast(rhs);
377 cast([
378 arr[0].wrapping_shl(rhs[0] as u32),
379 arr[1].wrapping_shl(rhs[1] as u32),
380 arr[2].wrapping_shl(rhs[2] as u32),
381 arr[3].wrapping_shl(rhs[3] as u32),
382 ])
383 }
384 }
385 }
386}
387
388#[expect(deprecated)]
389impl CmpEq for i32x4 {
390 type Output = Self;
391 #[inline]
392 fn simd_eq(self, rhs: Self) -> Self::Output {
393 pick! {
394 if #[cfg(target_feature="sse2")] {
395 Self { sse: cmp_eq_mask_i32_m128i(self.sse, rhs.sse) }
396 } else if #[cfg(target_feature="simd128")] {
397 Self { simd: i32x4_eq(self.simd, rhs.simd) }
398 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
399 unsafe {Self { neon: vreinterpretq_s32_u32(vceqq_s32(self.neon, rhs.neon)) }}
400 } else {
401 Self { arr: [
402 if self.arr[0] == rhs.arr[0] { -1 } else { 0 },
403 if self.arr[1] == rhs.arr[1] { -1 } else { 0 },
404 if self.arr[2] == rhs.arr[2] { -1 } else { 0 },
405 if self.arr[3] == rhs.arr[3] { -1 } else { 0 },
406 ]}
407 }
408 }
409 }
410}
411
412#[expect(deprecated)]
413impl CmpGt for i32x4 {
414 type Output = Self;
415 #[inline]
416 fn simd_gt(self, rhs: Self) -> Self::Output {
417 pick! {
418 if #[cfg(target_feature="sse2")] {
419 Self { sse: cmp_gt_mask_i32_m128i(self.sse, rhs.sse) }
420 } else if #[cfg(target_feature="simd128")] {
421 Self { simd: i32x4_gt(self.simd, rhs.simd) }
422 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
423 unsafe {Self { neon: vreinterpretq_s32_u32(vcgtq_s32(self.neon, rhs.neon)) }}
424 } else {
425 Self { arr: [
426 if self.arr[0] > rhs.arr[0] { -1 } else { 0 },
427 if self.arr[1] > rhs.arr[1] { -1 } else { 0 },
428 if self.arr[2] > rhs.arr[2] { -1 } else { 0 },
429 if self.arr[3] > rhs.arr[3] { -1 } else { 0 },
430 ]}
431 }
432 }
433 }
434}
435
436#[expect(deprecated)]
437impl CmpLt for i32x4 {
438 type Output = Self;
439 #[inline]
440 fn simd_lt(self, rhs: Self) -> Self::Output {
441 pick! {
442 if #[cfg(target_feature="sse2")] {
443 Self { sse: cmp_lt_mask_i32_m128i(self.sse, rhs.sse) }
444 } else if #[cfg(target_feature="simd128")] {
445 Self { simd: i32x4_lt(self.simd, rhs.simd) }
446 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
447 unsafe {Self { neon: vreinterpretq_s32_u32(vcltq_s32(self.neon, rhs.neon)) }}
448 } else {
449 Self { arr: [
450 if self.arr[0] < rhs.arr[0] { -1 } else { 0 },
451 if self.arr[1] < rhs.arr[1] { -1 } else { 0 },
452 if self.arr[2] < rhs.arr[2] { -1 } else { 0 },
453 if self.arr[3] < rhs.arr[3] { -1 } else { 0 },
454 ]}
455 }
456 }
457 }
458}
459
460#[expect(deprecated)]
461impl CmpNe for i32x4 {
462 type Output = Self;
463 #[inline]
464 fn simd_ne(self, rhs: Self) -> Self::Output {
465 pick! {
466 if #[cfg(target_feature="sse2")] {
467 !self.simd_eq(rhs)
468 } else if #[cfg(target_feature="simd128")] {
469 Self { simd: i32x4_ne(self.simd, rhs.simd) }
470 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
471 !self.simd_eq(rhs)
472 } else {
473 Self { arr: [
474 if self.arr[0] != rhs.arr[0] { -1 } else { 0 },
475 if self.arr[1] != rhs.arr[1] { -1 } else { 0 },
476 if self.arr[2] != rhs.arr[2] { -1 } else { 0 },
477 if self.arr[3] != rhs.arr[3] { -1 } else { 0 },
478 ]}
479 }
480 }
481 }
482}
483
484#[expect(deprecated)]
485impl CmpLe for i32x4 {
486 type Output = Self;
487 #[inline]
488 fn simd_le(self, rhs: Self) -> Self::Output {
489 pick! {
490 if #[cfg(target_feature="sse2")] {
491 !self.simd_gt(rhs)
492 } else if #[cfg(target_feature="simd128")] {
493 Self { simd: i32x4_le(self.simd, rhs.simd) }
494 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
495 !self.simd_gt(rhs)
496 } else {
497 Self { arr: [
498 if self.arr[0] <= rhs.arr[0] { -1 } else { 0 },
499 if self.arr[1] <= rhs.arr[1] { -1 } else { 0 },
500 if self.arr[2] <= rhs.arr[2] { -1 } else { 0 },
501 if self.arr[3] <= rhs.arr[3] { -1 } else { 0 },
502 ]}
503 }
504 }
505 }
506}
507
508#[expect(deprecated)]
509impl CmpGe for i32x4 {
510 type Output = Self;
511 #[inline]
512 fn simd_ge(self, rhs: Self) -> Self::Output {
513 pick! {
514 if #[cfg(target_feature="sse2")] {
515 !self.simd_lt(rhs)
516 } else if #[cfg(target_feature="simd128")] {
517 Self { simd: i32x4_ge(self.simd, rhs.simd) }
518 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
519 !self.simd_lt(rhs)
520 } else {
521 Self { arr: [
522 if self.arr[0] >= rhs.arr[0] { -1 } else { 0 },
523 if self.arr[1] >= rhs.arr[1] { -1 } else { 0 },
524 if self.arr[2] >= rhs.arr[2] { -1 } else { 0 },
525 if self.arr[3] >= rhs.arr[3] { -1 } else { 0 },
526 ]}
527 }
528 }
529 }
530}
531
532impl i32x4 {
533 #[inline]
534 #[must_use]
535 pub const fn new(array: [i32; 4]) -> Self {
536 unsafe { core::mem::transmute(array) }
537 }
538
539 simd_comparison_fns!();
540
541 #[inline]
542 #[must_use]
543 pub fn blend(self, t: Self, f: Self) -> Self {
544 pick! {
545 if #[cfg(target_feature="sse4.1")] {
546 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
547 } else if #[cfg(target_feature="simd128")] {
548 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
549 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
550 unsafe {Self { neon: vbslq_s32(vreinterpretq_u32_s32(self.neon), t.neon, f.neon) }}
551 } else {
552 generic_bit_blend(self, t, f)
553 }
554 }
555 }
556
557 #[inline]
560 #[must_use]
561 pub fn is_positive(self) -> Self {
562 pick! {
563 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
564 Self { neon: unsafe { vreinterpretq_s32_u32(vcgtzq_s32(self.neon)) } }
565 } else {
566 self.simd_gt(Self::ZERO)
567 }
568 }
569 }
570
571 #[inline]
574 #[must_use]
575 pub fn is_negative(self) -> Self {
576 pick! {
577 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
578 Self { neon: unsafe { vreinterpretq_s32_u32(vcltzq_s32(self.neon)) } }
579 } else {
580 self.simd_lt(Self::ZERO)
581 }
582 }
583 }
584
585 #[inline]
591 #[must_use]
592 pub fn mul_widen(self, rhs: Self) -> i64x4 {
593 pick! {
594 if #[cfg(target_feature="avx2")] {
595 let a = convert_to_i64_m256i_from_i32_m128i(self.sse);
596 let b = convert_to_i64_m256i_from_i32_m128i(rhs.sse);
597 cast(mul_i64_low_bits_m256i(a, b))
598 } else if #[cfg(target_feature="sse4.1")] {
599 let evenp = mul_widen_i32_odd_m128i(self.sse, rhs.sse);
600
601 let oddp = mul_widen_i32_odd_m128i(
602 shr_imm_u64_m128i::<32>(self.sse),
603 shr_imm_u64_m128i::<32>(rhs.sse));
604
605 i64x4 {
606 a: i64x2 { sse: unpack_low_i64_m128i(evenp, oddp)},
607 b: i64x2 { sse: unpack_high_i64_m128i(evenp, oddp)}
608 }
609 } else if #[cfg(target_feature="simd128")] {
610 i64x4 {
611 a: i64x2 { simd: i64x2_extmul_low_i32x4(self.simd, rhs.simd) },
612 b: i64x2 { simd: i64x2_extmul_high_i32x4(self.simd, rhs.simd) },
613 }
614 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
615 unsafe {
616 i64x4 { a: i64x2 { neon: vmull_s32(vget_low_s32(self.neon), vget_low_s32(rhs.neon)) },
617 b: i64x2 { neon: vmull_s32(vget_high_s32(self.neon), vget_high_s32(rhs.neon)) } }
618 }
619 } else {
620 let a: [i32; 4] = cast(self);
621 let b: [i32; 4] = cast(rhs);
622 cast([
623 i64::from(a[0]) * i64::from(b[0]),
624 i64::from(a[1]) * i64::from(b[1]),
625 i64::from(a[2]) * i64::from(b[2]),
626 i64::from(a[3]) * i64::from(b[3]),
627 ])
628 }
629 }
630 }
631
632 #[inline]
633 #[must_use]
634 pub fn abs(self) -> Self {
635 pick! {
636 if #[cfg(target_feature="ssse3")] {
637 Self { sse: abs_i32_m128i(self.sse) }
638 } else if #[cfg(target_feature="simd128")] {
639 Self { simd: i32x4_abs(self.simd) }
640 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
641 unsafe {Self { neon: vabsq_s32(self.neon) }}
642 } else {
643 let arr: [i32; 4] = cast(self);
644 cast([
645 arr[0].wrapping_abs(),
646 arr[1].wrapping_abs(),
647 arr[2].wrapping_abs(),
648 arr[3].wrapping_abs(),
649 ])
650 }
651 }
652 }
653
654 #[inline]
655 #[must_use]
656 pub fn unsigned_abs(self) -> u32x4 {
657 pick! {
658 if #[cfg(target_feature="ssse3")] {
659 u32x4 { sse: abs_i32_m128i(self.sse) }
660 } else if #[cfg(target_feature="simd128")] {
661 u32x4 { simd: i32x4_abs(self.simd) }
662 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
663 unsafe {u32x4 { neon: vreinterpretq_u32_s32(vabsq_s32(self.neon)) }}
664 } else {
665 let arr: [i32; 4] = cast(self);
666 cast([
667 arr[0].unsigned_abs(),
668 arr[1].unsigned_abs(),
669 arr[2].unsigned_abs(),
670 arr[3].unsigned_abs(),
671 ])
672 }
673 }
674 }
675
676 signed_fn_signum!();
677
678 #[inline]
680 #[must_use]
681 pub fn reduce_add(self) -> i32 {
682 pick! {
683 if #[cfg(target_feature="sse2")] {
684 let hi64 = unpack_high_i64_m128i(self.sse, self.sse);
685 let sum64 = add_i32_m128i(hi64, self.sse);
686 let hi32 = shuffle_ai_f32_all_m128i::<0b10_11_00_01>(sum64); let sum32 = add_i32_m128i(sum64, hi32);
688 get_i32_from_m128i_s(sum32)
689 } else {
690 let arr: [i32; 4] = cast(self);
691 arr[0].wrapping_add(arr[1]).wrapping_add(
692 arr[2].wrapping_add(arr[3]))
693 }
694 }
695 }
696
697 #[inline]
699 #[must_use]
700 pub fn reduce_max(self) -> i32 {
701 let arr: [i32; 4] = cast(self);
702 arr[0].max(arr[1]).max(arr[2].max(arr[3]))
703 }
704
705 #[inline]
707 #[must_use]
708 pub fn reduce_min(self) -> i32 {
709 let arr: [i32; 4] = cast(self);
710 arr[0].min(arr[1]).min(arr[2].min(arr[3]))
711 }
712
713 #[inline]
714 #[must_use]
715 pub fn max(self, rhs: Self) -> Self {
716 pick! {
717 if #[cfg(target_feature="sse4.1")] {
718 Self { sse: max_i32_m128i(self.sse, rhs.sse) }
719 } else if #[cfg(target_feature="simd128")] {
720 Self { simd: i32x4_max(self.simd, rhs.simd) }
721 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
722 unsafe {Self { neon: vmaxq_s32(self.neon, rhs.neon) }}
723 } else {
724 self.simd_lt(rhs).blend(rhs, self)
725 }
726 }
727 }
728 #[inline]
729 #[must_use]
730 pub fn min(self, rhs: Self) -> Self {
731 pick! {
732 if #[cfg(target_feature="sse4.1")] {
733 Self { sse: min_i32_m128i(self.sse, rhs.sse) }
734 } else if #[cfg(target_feature="simd128")] {
735 Self { simd: i32x4_min(self.simd, rhs.simd) }
736 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
737 unsafe {Self { neon: vminq_s32(self.neon, rhs.neon) }}
738 } else {
739 self.simd_lt(rhs).blend(self, rhs)
740 }
741 }
742 }
743
744 integer_fn_clamp!();
745
746 #[inline]
747 #[must_use]
748 pub fn saturating_add(self, rhs: Self) -> Self {
749 pick! {
750 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
751 let result = self + rhs;
752 let overflow = (!(self ^ rhs) & (self ^ result)).is_negative();
753 let negative = self.is_negative();
754
755 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
756 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
757 unsafe { Self { neon: vqaddq_s32(self.neon, rhs.neon) } }
758 } else {
759 Self {
760 arr: [
761 self.arr[0].saturating_add(rhs.arr[0]),
762 self.arr[1].saturating_add(rhs.arr[1]),
763 self.arr[2].saturating_add(rhs.arr[2]),
764 self.arr[3].saturating_add(rhs.arr[3]),
765 ],
766 }
767 }
768 }
769 }
770
771 #[inline]
772 #[must_use]
773 pub fn saturating_sub(self, rhs: Self) -> Self {
774 pick! {
775 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
776 let result = self - rhs;
777 let overflow = ((self ^ rhs) & (self ^ result)).is_negative();
778 let negative = self.is_negative();
779
780 overflow.blend(negative.blend(Self::MIN, Self::MAX), result)
781 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
782 unsafe { Self { neon: vqsubq_s32(self.neon, rhs.neon) } }
783 } else {
784 Self {
785 arr: [
786 self.arr[0].saturating_sub(rhs.arr[0]),
787 self.arr[1].saturating_sub(rhs.arr[1]),
788 self.arr[2].saturating_sub(rhs.arr[2]),
789 self.arr[3].saturating_sub(rhs.arr[3]),
790 ],
791 }
792 }
793 }
794 }
795
796 #[inline]
798 #[must_use]
799 pub fn saturating_mul(self, rhs: Self) -> Self {
800 pick! {
801 if #[cfg(target_feature="sse4.1")] {
802 let even_wide_mul = mul_widen_i32_odd_m128i(self.sse, rhs.sse);
803 let odd_wide_mul = mul_widen_i32_odd_m128i(
804 shuffle_ai_f32_all_m128i::<0b_00_11_00_01>(self.sse),
805 shuffle_ai_f32_all_m128i::<0b_00_11_00_01>(rhs.sse),
806 );
807
808 let ll_hh_1 = unpack_low_i32_m128i(even_wide_mul, odd_wide_mul);
809 let ll_hh_2 = unpack_high_i32_m128i(even_wide_mul, odd_wide_mul);
810 let low = Self { sse: unpack_low_i64_m128i(ll_hh_1, ll_hh_2) };
811 let high = Self { sse: unpack_high_i64_m128i(ll_hh_1, ll_hh_2) };
812
813 let no_overflow = high.simd_eq(low.is_negative());
814 let limit = Self::MAX ^ (self ^ rhs).is_negative();
815 no_overflow.blend(low, limit)
816 } else if #[cfg(target_feature="simd128")] {
817 let low_wide_mul = i64x2_extmul_low_i32x4(self.simd, rhs.simd);
818 let high_wide_mul = i64x2_extmul_high_i32x4(self.simd, rhs.simd);
819 let low = Self { simd: i32x4_shuffle::<0, 2, 4, 6>(low_wide_mul, high_wide_mul) };
820 let high = Self { simd: i32x4_shuffle::<1, 3, 5, 7>(low_wide_mul, high_wide_mul) };
821
822 let no_overflow = high.simd_eq(low.is_negative());
823 let limit = Self::MAX ^ (self ^ rhs).is_negative();
824 no_overflow.blend(low, limit)
825 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
826 unsafe {
827 let low_wide_mul = vreinterpretq_s32_s64(
828 vmull_s32(vget_low_s32(self.neon), vget_low_s32(rhs.neon)),
829 );
830 let high_wide_mul = vreinterpretq_s32_s64(
831 vmull_s32(vget_high_s32(self.neon), vget_high_s32(rhs.neon)),
832 );
833 let low_high = vuzpq_s32(low_wide_mul, high_wide_mul);
834 let low = Self { neon: low_high.0 };
835 let high = Self { neon: low_high.1 };
836
837 let no_overflow = high.simd_eq(low.is_negative());
838 let limit = Self::MAX ^ (self ^ rhs).is_negative();
839 no_overflow.blend(low, limit)
840 }
841 } else {
842 let self_array = self.to_array();
843 let rhs_array = rhs.to_array();
844
845 Self::new([
846 self_array[0].saturating_mul(rhs_array[0]),
847 self_array[1].saturating_mul(rhs_array[1]),
848 self_array[2].saturating_mul(rhs_array[2]),
849 self_array[3].saturating_mul(rhs_array[3]),
850 ])
851 }
852 }
853 }
854
855 integer_fn_saturating_div!([0, 1, 2, 3]);
856
857 #[inline]
858 #[must_use]
859 pub fn round_float(self) -> f32x4 {
860 pick! {
861 if #[cfg(target_feature="sse2")] {
862 cast(convert_to_m128_from_i32_m128i(self.sse))
863 } else if #[cfg(target_feature="simd128")] {
864 cast(Self { simd: f32x4_convert_i32x4(self.simd) })
865 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
866 cast(unsafe {Self { neon: vreinterpretq_s32_f32(vcvtq_f32_s32(self.neon)) }})
867 } else {
868 let arr: [i32; 4] = cast(self);
869 cast([
870 arr[0] as f32,
871 arr[1] as f32,
872 arr[2] as f32,
873 arr[3] as f32,
874 ])
875 }
876 }
877 }
878
879 #[inline]
880 #[must_use]
881 #[doc(alias("movemask", "move_mask"))]
882 pub fn to_bitmask(self) -> u32 {
883 pick! {
884 if #[cfg(target_feature="sse2")] {
885 move_mask_m128(cast(self.sse)) as u32
887 } else if #[cfg(target_feature="simd128")] {
888 u32x4_bitmask(self.simd) as u32
889 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
890 unsafe
891 {
892 let masked = vcltq_s32(self.neon, vdupq_n_s32(0));
894
895 let selectbit : uint32x4_t = core::mem::transmute([1u32, 2, 4, 8]);
897 let r = vandq_u32(masked, selectbit);
898
899 vaddvq_u32(r) as u32
901 }
902 } else {
903 ((self.arr[0] < 0) as u32) << 0 |
904 ((self.arr[1] < 0) as u32) << 1 |
905 ((self.arr[2] < 0) as u32) << 2 |
906 ((self.arr[3] < 0) as u32) << 3
907 }
908 }
909 }
910
911 #[inline]
912 #[must_use]
913 pub fn any(self) -> bool {
914 pick! {
915 if #[cfg(target_feature="sse2")] {
916 move_mask_m128(cast(self.sse)) != 0
918 } else if #[cfg(target_feature="simd128")] {
919 u32x4_bitmask(self.simd) != 0
920 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
921 unsafe {
923 vminvq_s32(self.neon) < 0
924 }
925 } else {
926 let v : [u64;2] = cast(self);
927 ((v[0] | v[1]) & 0x8000000080000000) != 0
928 }
929 }
930 }
931
932 #[inline]
933 #[must_use]
934 pub fn all(self) -> bool {
935 pick! {
936 if #[cfg(target_feature="sse2")] {
937 move_mask_m128(cast(self.sse)) == 0b1111
939 } else if #[cfg(target_feature="simd128")] {
940 u32x4_bitmask(self.simd) == 0b1111
941 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
942 unsafe {
944 vmaxvq_s32(self.neon) < 0
945 }
946 } else {
947 let v : [u64;2] = cast(self);
948 (v[0] & v[1] & 0x8000000080000000) == 0x8000000080000000
949 }
950 }
951 }
952
953 #[inline]
954 #[must_use]
955 pub fn none(self) -> bool {
956 !self.any()
957 }
958
959 #[must_use]
961 #[inline]
962 pub fn transpose(data: [i32x4; 4]) -> [i32x4; 4] {
963 pick! {
964 if #[cfg(target_feature="sse")] {
965 let mut e0 = data[0];
966 let mut e1 = data[1];
967 let mut e2 = data[2];
968 let mut e3 = data[3];
969
970 transpose_four_m128(
971 cast_mut(&mut e0.sse),
972 cast_mut(&mut e1.sse),
973 cast_mut(&mut e2.sse),
974 cast_mut(&mut e3.sse),
975 );
976
977 [e0, e1, e2, e3]
978 } else {
979 #[inline(always)]
980 fn transpose_column(data: &[i32x4; 4], index: usize) -> i32x4 {
981 i32x4::new([
982 data[0].as_array()[index],
983 data[1].as_array()[index],
984 data[2].as_array()[index],
985 data[3].as_array()[index],
986 ])
987 }
988
989 [
990 transpose_column(&data, 0),
991 transpose_column(&data, 1),
992 transpose_column(&data, 2),
993 transpose_column(&data, 3),
994 ]
995 }
996 }
997 }
998
999 #[inline]
1000 pub fn to_array(self) -> [i32; 4] {
1001 cast(self)
1002 }
1003
1004 #[inline]
1005 pub fn as_array(&self) -> &[i32; 4] {
1006 cast_ref(self)
1007 }
1008
1009 #[inline]
1010 pub fn as_mut_array(&mut self) -> &mut [i32; 4] {
1011 cast_mut(self)
1012 }
1013}