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 u32x4 { 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 u32x4 { pub(crate) simd: v128 }
14
15 impl Default for u32x4 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for u32x4 {
22 fn eq(&self, other: &Self) -> bool {
23 u32x4_all_true(u32x4_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for u32x4 { }
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 u32x4 { pub(crate) neon : uint32x4_t }
33
34 impl Default for u32x4 {
35 #[inline]
36 fn default() -> Self {
37 Self::splat(0)
38 }
39 }
40
41 impl PartialEq for u32x4 {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 unsafe { vminvq_u32(vceqq_u32(self.neon, other.neon))==u32::MAX }
45 }
46 }
47
48 impl Eq for u32x4 { }
49} else {
50 #[derive(Default, Clone, Copy, PartialEq, Eq)]
51 #[repr(C, align(16))]
52 pub struct u32x4 { arr: [u32;4] }
53 }
54}
55
56int_uint_consts!(u32, 4, u32x4, 128);
57
58unsafe impl Zeroable for u32x4 {}
59unsafe impl Pod for u32x4 {}
60
61impl AlignTo for u32x4 {
62 type Elem = u32;
63}
64
65impl Add for u32x4 {
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: u32x4_add(self.simd, rhs.simd) }
74 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
75 unsafe { Self { neon: vaddq_u32(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 u32x4 {
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: u32x4_sub(self.simd, rhs.simd) }
97 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
98 unsafe {Self { neon: vsubq_u32(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 u32x4 {
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: u32x4_mul(self.simd, rhs.simd) }
120 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
121 unsafe {Self { neon: vmulq_u32(self.neon, rhs.neon) }}
122 } else {
123 let arr1: [u32; 4] = cast(self);
124 let arr2: [u32; 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!(u32, u32x4, [0, 1, 2, 3]);
137
138impl Add<u32> for u32x4 {
139 type Output = Self;
140 #[inline]
141 fn add(self, rhs: u32) -> Self::Output {
142 self.add(Self::splat(rhs))
143 }
144}
145
146impl Sub<u32> for u32x4 {
147 type Output = Self;
148 #[inline]
149 fn sub(self, rhs: u32) -> Self::Output {
150 self.sub(Self::splat(rhs))
151 }
152}
153
154impl Mul<u32> for u32x4 {
155 type Output = Self;
156 #[inline]
157 fn mul(self, rhs: u32) -> Self::Output {
158 self.mul(Self::splat(rhs))
159 }
160}
161
162impl Add<u32x4> for u32 {
163 type Output = u32x4;
164 #[inline]
165 fn add(self, rhs: u32x4) -> Self::Output {
166 u32x4::splat(self).add(rhs)
167 }
168}
169
170impl Sub<u32x4> for u32 {
171 type Output = u32x4;
172 #[inline]
173 fn sub(self, rhs: u32x4) -> Self::Output {
174 u32x4::splat(self).sub(rhs)
175 }
176}
177
178impl Mul<u32x4> for u32 {
179 type Output = u32x4;
180 #[inline]
181 fn mul(self, rhs: u32x4) -> Self::Output {
182 u32x4::splat(self).mul(rhs)
183 }
184}
185
186impl BitAnd for u32x4 {
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_u32(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 u32x4 {
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_u32(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 u32x4 {
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_u32(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_u32x4 {
256 ($($shift_type:ty),+ $(,)?) => {
257 $(impl Shl<$shift_type> for u32x4 {
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: u32x4_shl(self.simd, rhs as u32) }
268 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
269 unsafe {Self { neon: vshlq_u32(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_u32x4!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
285
286macro_rules! impl_shr_t_for_u32x4 {
287 ($($shift_type:ty),+ $(,)?) => {
288 $(impl Shr<$shift_type> for u32x4 {
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_u32_m128i(self.sse, shift) }
297 } else if #[cfg(target_feature="simd128")] {
298 Self { simd: u32x4_shr(self.simd, rhs as u32) }
299 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
300 unsafe {Self { neon: vshlq_u32(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_u32x4!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
316
317impl Shr<u32x4> for u32x4 {
323 type Output = Self;
324 #[inline]
325 fn shr(self, rhs: u32x4) -> Self::Output {
326 pick! {
327 if #[cfg(target_feature="avx2")] {
328 let shift_by = bitand_m128i(rhs.sse, set_splat_i32_m128i(31));
330 Self { sse: shr_each_u32_m128i(self.sse, shift_by) }
331 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
332 unsafe {
333 let shift_by = vnegq_s32(vreinterpretq_s32_u32(vandq_u32(rhs.neon, vmovq_n_u32(31))));
336 Self { neon: vshlq_u32(self.neon, shift_by) }
337 }
338 } else {
339 let arr: [u32; 4] = cast(self);
340 let rhs: [u32; 4] = cast(rhs);
341 cast([
342 arr[0].wrapping_shr(rhs[0]),
343 arr[1].wrapping_shr(rhs[1]),
344 arr[2].wrapping_shr(rhs[2]),
345 arr[3].wrapping_shr(rhs[3]),
346 ])
347 }
348 }
349 }
350}
351
352impl Shl<u32x4> for u32x4 {
358 type Output = Self;
359 #[inline]
360 fn shl(self, rhs: u32x4) -> Self::Output {
361 pick! {
362 if #[cfg(target_feature="avx2")] {
363 let shift_by = bitand_m128i(rhs.sse, set_splat_i32_m128i(31));
365 Self { sse: shl_each_u32_m128i(self.sse, shift_by) }
366 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
367 unsafe {
368 let shift_by = vreinterpretq_s32_u32(vandq_u32(rhs.neon, vmovq_n_u32(31)));
370 Self { neon: vshlq_u32(self.neon, shift_by) }
371 }
372 } else {
373 let arr: [u32; 4] = cast(self);
374 let rhs: [u32; 4] = cast(rhs);
375 cast([
376 arr[0].wrapping_shl(rhs[0]),
377 arr[1].wrapping_shl(rhs[1]),
378 arr[2].wrapping_shl(rhs[2]),
379 arr[3].wrapping_shl(rhs[3]),
380 ])
381 }
382 }
383 }
384}
385
386#[expect(deprecated)]
387impl CmpEq for u32x4 {
388 type Output = Self;
389 #[inline]
390 fn simd_eq(self, rhs: Self) -> Self::Output {
391 pick! {
392 if #[cfg(target_feature="sse2")] {
393 Self { sse: cmp_eq_mask_i32_m128i(self.sse, rhs.sse) }
394 } else if #[cfg(target_feature="simd128")] {
395 Self { simd: u32x4_eq(self.simd, rhs.simd) }
396 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
397 unsafe {Self { neon: vceqq_u32(self.neon, rhs.neon) }}
398 } else {
399 Self { arr: [
400 if self.arr[0] == rhs.arr[0] { u32::MAX } else { 0 },
401 if self.arr[1] == rhs.arr[1] { u32::MAX } else { 0 },
402 if self.arr[2] == rhs.arr[2] { u32::MAX } else { 0 },
403 if self.arr[3] == rhs.arr[3] { u32::MAX } else { 0 },
404 ]}
405 }
406 }
407 }
408}
409
410#[expect(deprecated)]
411impl CmpGt for u32x4 {
412 type Output = Self;
413 #[inline]
414 fn simd_gt(self, rhs: Self) -> Self::Output {
415 pick! {
416 if #[cfg(target_feature="sse2")] {
417 let h = u32x4::splat(1 << 31);
419 Self { sse: cmp_gt_mask_i32_m128i((self ^ h).sse, (rhs ^ h).sse) }
420 } else if #[cfg(target_feature="simd128")] {
421 Self { simd: u32x4_gt(self.simd, rhs.simd) }
422 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
423 unsafe {Self { neon: vcgtq_u32(self.neon, rhs.neon) }}
424 } else {
425 Self { arr: [
426 if self.arr[0] > rhs.arr[0] { u32::MAX } else { 0 },
427 if self.arr[1] > rhs.arr[1] { u32::MAX } else { 0 },
428 if self.arr[2] > rhs.arr[2] { u32::MAX } else { 0 },
429 if self.arr[3] > rhs.arr[3] { u32::MAX } else { 0 },
430 ]}
431 }
432 }
433 }
434}
435
436#[expect(deprecated)]
437impl CmpLt for u32x4 {
438 type Output = Self;
439 #[inline]
440 fn simd_lt(self, rhs: Self) -> Self::Output {
441 rhs.simd_gt(self)
443 }
444}
445
446#[expect(deprecated)]
447impl CmpNe for u32x4 {
448 type Output = Self;
449 #[inline]
450 fn simd_ne(self, rhs: Self) -> Self::Output {
451 pick! {
452 if #[cfg(target_feature="sse2")] {
453 !self.simd_eq(rhs)
454 } else if #[cfg(target_feature="simd128")] {
455 Self { simd: u32x4_ne(self.simd, rhs.simd) }
456 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
457 !self.simd_eq(rhs)
458 } else {
459 Self { arr: [
460 if self.arr[0] != rhs.arr[0] { u32::MAX } else { 0 },
461 if self.arr[1] != rhs.arr[1] { u32::MAX } else { 0 },
462 if self.arr[2] != rhs.arr[2] { u32::MAX } else { 0 },
463 if self.arr[3] != rhs.arr[3] { u32::MAX } else { 0 },
464 ]}
465 }
466 }
467 }
468}
469
470#[expect(deprecated)]
471impl CmpLe for u32x4 {
472 type Output = Self;
473 #[inline]
474 fn simd_le(self, rhs: Self) -> Self::Output {
475 pick! {
476 if #[cfg(target_feature="sse2")] {
477 !self.simd_gt(rhs)
478 } else if #[cfg(target_feature="simd128")] {
479 Self { simd: u32x4_le(self.simd, rhs.simd) }
480 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
481 !self.simd_gt(rhs)
482 } else {
483 Self { arr: [
484 if self.arr[0] <= rhs.arr[0] { u32::MAX } else { 0 },
485 if self.arr[1] <= rhs.arr[1] { u32::MAX } else { 0 },
486 if self.arr[2] <= rhs.arr[2] { u32::MAX } else { 0 },
487 if self.arr[3] <= rhs.arr[3] { u32::MAX } else { 0 },
488 ]}
489 }
490 }
491 }
492}
493
494#[expect(deprecated)]
495impl CmpGe for u32x4 {
496 type Output = Self;
497 #[inline]
498 fn simd_ge(self, rhs: Self) -> Self::Output {
499 pick! {
500 if #[cfg(target_feature="sse2")] {
501 !self.simd_lt(rhs)
502 } else if #[cfg(target_feature="simd128")] {
503 Self { simd: u32x4_ge(self.simd, rhs.simd) }
504 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
505 !self.simd_lt(rhs)
506 } else {
507 Self { arr: [
508 if self.arr[0] >= rhs.arr[0] { u32::MAX } else { 0 },
509 if self.arr[1] >= rhs.arr[1] { u32::MAX } else { 0 },
510 if self.arr[2] >= rhs.arr[2] { u32::MAX } else { 0 },
511 if self.arr[3] >= rhs.arr[3] { u32::MAX } else { 0 },
512 ]}
513 }
514 }
515 }
516}
517
518impl u32x4 {
519 #[inline]
520 #[must_use]
521 pub const fn new(array: [u32; 4]) -> Self {
522 unsafe { core::mem::transmute(array) }
523 }
524
525 simd_comparison_fns!();
526
527 #[inline]
531 #[must_use]
532 pub fn mul_keep_high(self, rhs: Self) -> Self {
533 pick! {
534 if #[cfg(target_feature="avx2")] {
535 let a = convert_to_i64_m256i_from_u32_m128i(self.sse);
536 let b = convert_to_i64_m256i_from_u32_m128i(rhs.sse);
537 let r = mul_u64_low_bits_m256i(a, b);
538
539 let b : [u32;8] = cast(r);
541 cast([b[1],b[3],b[5],b[7]])
542 } else if #[cfg(target_feature="sse2")] {
543 let evenp = mul_widen_u32_odd_m128i(self.sse, rhs.sse);
544
545 let oddp = mul_widen_u32_odd_m128i(
546 shr_imm_u64_m128i::<32>(self.sse),
547 shr_imm_u64_m128i::<32>(rhs.sse));
548
549 let a : [u32;4]= cast(evenp);
551 let b : [u32;4]= cast(oddp);
552 cast([a[1],b[1],a[3],b[3]])
553
554 } else if #[cfg(target_feature="simd128")] {
555 let low = u64x2_extmul_low_u32x4(self.simd, rhs.simd);
556 let high = u64x2_extmul_high_u32x4(self.simd, rhs.simd);
557
558 Self { simd: u32x4_shuffle::<1, 3, 5, 7>(low, high) }
559 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
560 unsafe {
561 let l = vmull_u32(vget_low_u32(self.neon), vget_low_u32(rhs.neon));
562 let h = vmull_u32(vget_high_u32(self.neon), vget_high_u32(rhs.neon));
563 u32x4 { neon: vcombine_u32(vshrn_n_u64(l,32), vshrn_n_u64(h,32)) }
564 }
565 } else {
566 let a: [u32; 4] = cast(self);
567 let b: [u32; 4] = cast(rhs);
568 cast([
569 ((u64::from(a[0]) * u64::from(b[0])) >> 32) as u32,
570 ((u64::from(a[1]) * u64::from(b[1])) >> 32) as u32,
571 ((u64::from(a[2]) * u64::from(b[2])) >> 32) as u32,
572 ((u64::from(a[3]) * u64::from(b[3])) >> 32) as u32,
573 ])
574 }
575 }
576 }
577
578 #[inline]
584 #[must_use]
585 pub fn mul_widen(self, rhs: Self) -> u64x4 {
586 pick! {
587 if #[cfg(target_feature="avx2")] {
588 let a = convert_to_i64_m256i_from_i32_m128i(self.sse);
590 let b = convert_to_i64_m256i_from_i32_m128i(rhs.sse);
591 cast(mul_u64_low_bits_m256i(a, b))
592 } else if #[cfg(target_feature="sse2")] {
593 let evenp = mul_widen_u32_odd_m128i(self.sse, rhs.sse);
594
595 let oddp = mul_widen_u32_odd_m128i(
596 shr_imm_u64_m128i::<32>(self.sse),
597 shr_imm_u64_m128i::<32>(rhs.sse));
598
599 u64x4 {
600 a: u64x2 { sse: unpack_low_i64_m128i(evenp, oddp)},
601 b: u64x2 { sse: unpack_high_i64_m128i(evenp, oddp)}
602 }
603 } else if #[cfg(target_feature="simd128")] {
604 u64x4 {
605 a: u64x2 { simd: u64x2_extmul_low_u32x4(self.simd, rhs.simd) },
606 b: u64x2 { simd: u64x2_extmul_high_u32x4(self.simd, rhs.simd) },
607 }
608 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
609 unsafe {
610 u64x4 { a: u64x2 { neon: vmull_u32(vget_low_u32(self.neon), vget_low_u32(rhs.neon)) },
611 b: u64x2 { neon: vmull_u32(vget_high_u32(self.neon), vget_high_u32(rhs.neon)) } }
612 }
613 } else {
614 let a: [u32; 4] = cast(self);
615 let b: [u32; 4] = cast(rhs);
616 cast([
617 u64::from(a[0]) * u64::from(b[0]),
618 u64::from(a[1]) * u64::from(b[1]),
619 u64::from(a[2]) * u64::from(b[2]),
620 u64::from(a[3]) * u64::from(b[3]),
621 ])
622 }
623 }
624 }
625
626 #[inline]
627 #[must_use]
628 pub fn blend(self, t: Self, f: Self) -> Self {
629 pick! {
630 if #[cfg(target_feature="sse4.1")] {
631 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
632 } else if #[cfg(target_feature="simd128")] {
633 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
634 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
635 unsafe {Self { neon: vbslq_u32(self.neon, t.neon, f.neon) }}
636 } else {
637 generic_bit_blend(self, t, f)
638 }
639 }
640 }
641
642 #[inline]
643 #[must_use]
644 pub fn reduce_add(self) -> u32 {
645 cast(i32x4::reduce_add(cast(self)))
646 }
647
648 #[inline]
649 #[must_use]
650 pub fn reduce_max(self) -> u32 {
651 let arr: [u32; 4] = cast(self);
652 arr[0].max(arr[1]).max(arr[2].max(arr[3]))
653 }
654
655 #[inline]
656 #[must_use]
657 pub fn reduce_min(self) -> u32 {
658 let arr: [u32; 4] = cast(self);
659 arr[0].min(arr[1]).min(arr[2].min(arr[3]))
660 }
661
662 #[inline]
663 #[must_use]
664 pub fn max(self, rhs: Self) -> Self {
665 pick! {
666 if #[cfg(target_feature="sse4.1")] {
667 Self { sse: max_u32_m128i(self.sse, rhs.sse) }
668 } else if #[cfg(target_feature="simd128")] {
669 Self { simd: u32x4_max(self.simd, rhs.simd) }
670 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
671 unsafe {Self { neon: vmaxq_u32(self.neon, rhs.neon) }}
672 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
673 unsafe {Self { neon: vmaxq_u16(self.neon, rhs.neon) }}
674 } else {
675 let arr: [u32; 4] = cast(self);
676 let rhs: [u32; 4] = cast(rhs);
677 cast([
678 arr[0].max(rhs[0]),
679 arr[1].max(rhs[1]),
680 arr[2].max(rhs[2]),
681 arr[3].max(rhs[3]),
682 ])
683 }
684 }
685 }
686 #[inline]
687 #[must_use]
688 pub fn min(self, rhs: Self) -> Self {
689 pick! {
690 if #[cfg(target_feature="sse4.1")] {
691 Self { sse: min_u32_m128i(self.sse, rhs.sse) }
692 } else if #[cfg(target_feature="simd128")] {
693 Self { simd: u32x4_min(self.simd, rhs.simd) }
694 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
695 unsafe {Self { neon: vminq_u32(self.neon, rhs.neon) }}
696 } else {
697 let arr: [u32; 4] = cast(self);
698 let rhs: [u32; 4] = cast(rhs);
699 cast([
700 arr[0].min(rhs[0]),
701 arr[1].min(rhs[1]),
702 arr[2].min(rhs[2]),
703 arr[3].min(rhs[3]),
704 ])
705 }
706 }
707 }
708
709 integer_fn_clamp!();
710
711 #[inline]
712 #[must_use]
713 pub fn saturating_add(self, rhs: Self) -> Self {
714 pick! {
715 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
716 let result = self + rhs;
717 result.simd_lt(self).blend(Self::MAX, result)
718 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
719 unsafe { Self { neon: vqaddq_u32(self.neon, rhs.neon) } }
720 } else {
721 Self {
722 arr: [
723 self.arr[0].saturating_add(rhs.arr[0]),
724 self.arr[1].saturating_add(rhs.arr[1]),
725 self.arr[2].saturating_add(rhs.arr[2]),
726 self.arr[3].saturating_add(rhs.arr[3]),
727 ],
728 }
729 }
730 }
731 }
732
733 #[inline]
734 #[must_use]
735 pub fn saturating_sub(self, rhs: Self) -> Self {
736 pick! {
737 if #[cfg(any(target_feature="sse2", target_feature="simd128"))] {
738 let result = self - rhs;
739 result.simd_gt(self).blend(Self::MIN, result)
740 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
741 unsafe { Self { neon: vqsubq_u32(self.neon, rhs.neon) } }
742 } else {
743 Self {
744 arr: [
745 self.arr[0].saturating_sub(rhs.arr[0]),
746 self.arr[1].saturating_sub(rhs.arr[1]),
747 self.arr[2].saturating_sub(rhs.arr[2]),
748 self.arr[3].saturating_sub(rhs.arr[3]),
749 ],
750 }
751 }
752 }
753 }
754
755 #[inline]
757 #[must_use]
758 pub fn saturating_mul(self, rhs: Self) -> Self {
759 pick! {
760 if #[cfg(target_feature="sse2")] {
761 let even_wide_mul = mul_widen_u32_odd_m128i(self.sse, rhs.sse);
762 let odd_wide_mul = mul_widen_u32_odd_m128i(
763 shuffle_ai_f32_all_m128i::<0b_00_11_00_01>(self.sse),
764 shuffle_ai_f32_all_m128i::<0b_00_11_00_01>(rhs.sse),
765 );
766
767 let ll_hh_1 = unpack_low_i32_m128i(even_wide_mul, odd_wide_mul);
768 let ll_hh_2 = unpack_high_i32_m128i(even_wide_mul, odd_wide_mul);
769 let low = Self { sse: unpack_low_i64_m128i(ll_hh_1, ll_hh_2) };
770 let high = Self { sse: unpack_high_i64_m128i(ll_hh_1, ll_hh_2) };
771
772 let no_overflow = high.simd_eq(Self::ZERO);
773 no_overflow.blend(low, Self::MAX)
774 } else if #[cfg(target_feature="simd128")] {
775 let low_wide_mul = u64x2_extmul_low_u32x4(self.simd, rhs.simd);
776 let high_wide_mul = u64x2_extmul_high_u32x4(self.simd, rhs.simd);
777 let low = Self { simd: u32x4_shuffle::<0, 2, 4, 6>(low_wide_mul, high_wide_mul) };
778 let high = Self { simd: u32x4_shuffle::<1, 3, 5, 7>(low_wide_mul, high_wide_mul) };
779
780 let no_overflow = high.simd_eq(Self::ZERO);
781 no_overflow.blend(low, Self::MAX)
782 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
783 unsafe {
784 let low_wide_mul = vreinterpretq_u32_u64(
785 vmull_u32(vget_low_u32(self.neon), vget_low_u32(rhs.neon)),
786 );
787 let high_wide_mul = vreinterpretq_u32_u64(
788 vmull_u32(vget_high_u32(self.neon), vget_high_u32(rhs.neon)),
789 );
790 let low_high = vuzpq_u32(low_wide_mul, high_wide_mul);
791 let low = Self { neon: low_high.0 };
792 let high = Self { neon: low_high.1 };
793
794 let no_overflow = high.simd_eq(Self::ZERO);
795 no_overflow.blend(low, Self::MAX)
796 }
797 } else {
798 let self_array = self.to_array();
799 let rhs_array = rhs.to_array();
800
801 Self::new([
802 self_array[0].saturating_mul(rhs_array[0]),
803 self_array[1].saturating_mul(rhs_array[1]),
804 self_array[2].saturating_mul(rhs_array[2]),
805 self_array[3].saturating_mul(rhs_array[3]),
806 ])
807 }
808 }
809 }
810
811 integer_fn_saturating_div!([0, 1, 2, 3]);
812
813 #[inline]
814 #[must_use]
815 pub fn any(self) -> bool {
816 pick! {
817 if #[cfg(target_feature="sse2")] {
818 (move_mask_i8_m128i(self.sse) & 0b1000100010001000) != 0
819 } else if #[cfg(target_feature="simd128")] {
820 u32x4_bitmask(self.simd) != 0
821 } else {
822 let v : [u64;2] = cast(self);
823 ((v[0] | v[1]) & 0x8000000080000000) != 0
824 }
825 }
826 }
827
828 #[inline]
829 #[must_use]
830 pub fn all(self) -> bool {
831 pick! {
832 if #[cfg(target_feature="sse2")] {
833 (move_mask_i8_m128i(self.sse) & 0b1000100010001000) == 0b1000100010001000
834 } else if #[cfg(target_feature="simd128")] {
835 u32x4_bitmask(self.simd) == 0b1111
836 } else {
837 let v : [u64;2] = cast(self);
838 (v[0] & v[1] & 0x8000000080000000) == 0x8000000080000000
839 }
840 }
841 }
842
843 #[inline]
844 #[must_use]
845 pub fn none(self) -> bool {
846 !self.any()
847 }
848
849 #[must_use]
851 #[inline]
852 pub fn transpose(data: [u32x4; 4]) -> [u32x4; 4] {
853 cast(i32x4::transpose(cast(data)))
854 }
855
856 #[inline]
857 #[must_use]
858 #[doc(alias("movemask", "move_mask"))]
859 pub fn to_bitmask(self) -> u32 {
860 i32x4::to_bitmask(cast(self))
861 }
862
863 #[inline]
864 pub fn to_array(self) -> [u32; 4] {
865 cast(self)
866 }
867
868 #[inline]
869 pub fn as_array(&self) -> &[u32; 4] {
870 cast_ref(self)
871 }
872
873 #[inline]
874 pub fn as_mut_array(&mut self) -> &mut [u32; 4] {
875 cast_mut(self)
876 }
877}