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 u8x16 { 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 u8x16 { pub(crate) simd: v128 }
14
15 impl Default for u8x16 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for u8x16 {
22 fn eq(&self, other: &Self) -> bool {
23 u8x16_all_true(u8x16_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for u8x16 { }
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 u8x16 { pub(crate) neon : uint8x16_t }
33
34 impl Default for u8x16 {
35 #[inline]
36 fn default() -> Self {
37 Self::splat(0)
38 }
39 }
40
41 impl PartialEq for u8x16 {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 unsafe { vminvq_u8(vceqq_u8(self.neon, other.neon))==u8::MAX }
45 }
46 }
47
48 impl Eq for u8x16 { }
49 } else {
50 #[derive(Default, Clone, Copy, PartialEq, Eq)]
51 #[repr(C, align(16))]
52 pub struct u8x16 { pub(crate) arr: [u8;16] }
53 }
54}
55
56int_uint_consts!(u8, 16, u8x16, 128);
57
58unsafe impl Zeroable for u8x16 {}
59unsafe impl Pod for u8x16 {}
60
61impl AlignTo for u8x16 {
62 type Elem = u8;
63}
64
65impl Add for u8x16 {
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_i8_m128i(self.sse, rhs.sse) }
72 } else if #[cfg(target_feature="simd128")] {
73 Self { simd: u8x16_add(self.simd, rhs.simd) }
74 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
75 unsafe { Self { neon: vaddq_u8(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 self.arr[4].wrapping_add(rhs.arr[4]),
83 self.arr[5].wrapping_add(rhs.arr[5]),
84 self.arr[6].wrapping_add(rhs.arr[6]),
85 self.arr[7].wrapping_add(rhs.arr[7]),
86 self.arr[8].wrapping_add(rhs.arr[8]),
87 self.arr[9].wrapping_add(rhs.arr[9]),
88 self.arr[10].wrapping_add(rhs.arr[10]),
89 self.arr[11].wrapping_add(rhs.arr[11]),
90 self.arr[12].wrapping_add(rhs.arr[12]),
91 self.arr[13].wrapping_add(rhs.arr[13]),
92 self.arr[14].wrapping_add(rhs.arr[14]),
93 self.arr[15].wrapping_add(rhs.arr[15]),
94 ]}
95 }
96 }
97 }
98}
99
100impl Sub for u8x16 {
101 type Output = Self;
102 #[inline]
103 fn sub(self, rhs: Self) -> Self::Output {
104 pick! {
105 if #[cfg(target_feature="sse2")] {
106 Self { sse: sub_i8_m128i(self.sse, rhs.sse) }
107 } else if #[cfg(target_feature="simd128")] {
108 Self { simd: u8x16_sub(self.simd, rhs.simd) }
109 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
110 unsafe {Self { neon: vsubq_u8(self.neon, rhs.neon) }}
111 } else {
112 Self { arr: [
113 self.arr[0].wrapping_sub(rhs.arr[0]),
114 self.arr[1].wrapping_sub(rhs.arr[1]),
115 self.arr[2].wrapping_sub(rhs.arr[2]),
116 self.arr[3].wrapping_sub(rhs.arr[3]),
117 self.arr[4].wrapping_sub(rhs.arr[4]),
118 self.arr[5].wrapping_sub(rhs.arr[5]),
119 self.arr[6].wrapping_sub(rhs.arr[6]),
120 self.arr[7].wrapping_sub(rhs.arr[7]),
121 self.arr[8].wrapping_sub(rhs.arr[8]),
122 self.arr[9].wrapping_sub(rhs.arr[9]),
123 self.arr[10].wrapping_sub(rhs.arr[10]),
124 self.arr[11].wrapping_sub(rhs.arr[11]),
125 self.arr[12].wrapping_sub(rhs.arr[12]),
126 self.arr[13].wrapping_sub(rhs.arr[13]),
127 self.arr[14].wrapping_sub(rhs.arr[14]),
128 self.arr[15].wrapping_sub(rhs.arr[15]),
129 ]}
130 }
131 }
132 }
133}
134
135impl Mul for u8x16 {
136 type Output = Self;
137
138 #[inline]
139 fn mul(self, rhs: Self) -> Self::Output {
140 pick! {
144 if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
145 unsafe { Self { neon: vmulq_u8(self.neon, rhs.neon) } }
146 } else {
147 let self_array: [u8; 16] = cast(self);
148 let rhs_array: [u8; 16] = cast(rhs);
149
150 Self::new([
151 self_array[0].wrapping_mul(rhs_array[0]),
152 self_array[1].wrapping_mul(rhs_array[1]),
153 self_array[2].wrapping_mul(rhs_array[2]),
154 self_array[3].wrapping_mul(rhs_array[3]),
155 self_array[4].wrapping_mul(rhs_array[4]),
156 self_array[5].wrapping_mul(rhs_array[5]),
157 self_array[6].wrapping_mul(rhs_array[6]),
158 self_array[7].wrapping_mul(rhs_array[7]),
159 self_array[8].wrapping_mul(rhs_array[8]),
160 self_array[9].wrapping_mul(rhs_array[9]),
161 self_array[10].wrapping_mul(rhs_array[10]),
162 self_array[11].wrapping_mul(rhs_array[11]),
163 self_array[12].wrapping_mul(rhs_array[12]),
164 self_array[13].wrapping_mul(rhs_array[13]),
165 self_array[14].wrapping_mul(rhs_array[14]),
166 self_array[15].wrapping_mul(rhs_array[15]),
167 ])
168 }
169 }
170 }
171}
172
173integer_impl_div_rem!(
174 u8,
175 u8x16,
176 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
177);
178
179impl Shl for u8x16 {
180 type Output = Self;
181
182 #[inline]
188 fn shl(self, rhs: Self) -> Self::Output {
189 pick! {
193 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
194 unsafe {
195 let shift_by = vreinterpretq_s8_u8(vandq_u8(rhs.neon, vmovq_n_u8(7)));
197 Self { neon: vshlq_u8(self.neon, shift_by) }
198 }
199 } else {
200 let self_array: [u8; 16] = cast(self);
201 let rhs_array: [u8; 16] = cast(rhs);
202
203 Self::new([
204 self_array[0].wrapping_shl(rhs_array[0] as u32),
205 self_array[1].wrapping_shl(rhs_array[1] as u32),
206 self_array[2].wrapping_shl(rhs_array[2] as u32),
207 self_array[3].wrapping_shl(rhs_array[3] as u32),
208 self_array[4].wrapping_shl(rhs_array[4] as u32),
209 self_array[5].wrapping_shl(rhs_array[5] as u32),
210 self_array[6].wrapping_shl(rhs_array[6] as u32),
211 self_array[7].wrapping_shl(rhs_array[7] as u32),
212 self_array[8].wrapping_shl(rhs_array[8] as u32),
213 self_array[9].wrapping_shl(rhs_array[9] as u32),
214 self_array[10].wrapping_shl(rhs_array[10] as u32),
215 self_array[11].wrapping_shl(rhs_array[11] as u32),
216 self_array[12].wrapping_shl(rhs_array[12] as u32),
217 self_array[13].wrapping_shl(rhs_array[13] as u32),
218 self_array[14].wrapping_shl(rhs_array[14] as u32),
219 self_array[15].wrapping_shl(rhs_array[15] as u32),
220 ])
221 }
222 }
223 }
224}
225
226impl Shr for u8x16 {
227 type Output = Self;
228
229 #[inline]
235 fn shr(self, rhs: Self) -> Self::Output {
236 pick! {
240 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
241 unsafe {
242 let neg_rhs = vnegq_s8(vreinterpretq_s8_u8(vandq_u8(rhs.neon, vmovq_n_u8(7))));
245 Self { neon: vshlq_u8(self.neon, neg_rhs) }
246 }
247 } else {
248 let self_array: [u8; 16] = cast(self);
249 let rhs_array: [u8; 16] = cast(rhs);
250
251 Self::new([
252 self_array[0].wrapping_shr(rhs_array[0] as u32),
253 self_array[1].wrapping_shr(rhs_array[1] as u32),
254 self_array[2].wrapping_shr(rhs_array[2] as u32),
255 self_array[3].wrapping_shr(rhs_array[3] as u32),
256 self_array[4].wrapping_shr(rhs_array[4] as u32),
257 self_array[5].wrapping_shr(rhs_array[5] as u32),
258 self_array[6].wrapping_shr(rhs_array[6] as u32),
259 self_array[7].wrapping_shr(rhs_array[7] as u32),
260 self_array[8].wrapping_shr(rhs_array[8] as u32),
261 self_array[9].wrapping_shr(rhs_array[9] as u32),
262 self_array[10].wrapping_shr(rhs_array[10] as u32),
263 self_array[11].wrapping_shr(rhs_array[11] as u32),
264 self_array[12].wrapping_shr(rhs_array[12] as u32),
265 self_array[13].wrapping_shr(rhs_array[13] as u32),
266 self_array[14].wrapping_shr(rhs_array[14] as u32),
267 self_array[15].wrapping_shr(rhs_array[15] as u32),
268 ])
269 }
270 }
271 }
272}
273
274impl Add<u8> for u8x16 {
275 type Output = Self;
276 #[inline]
277 fn add(self, rhs: u8) -> Self::Output {
278 self.add(Self::splat(rhs))
279 }
280}
281
282impl Sub<u8> for u8x16 {
283 type Output = Self;
284 #[inline]
285 fn sub(self, rhs: u8) -> Self::Output {
286 self.sub(Self::splat(rhs))
287 }
288}
289
290impl Mul<u8> for u8x16 {
291 type Output = Self;
292
293 #[inline]
294 fn mul(self, rhs: u8) -> Self::Output {
295 self * Self::splat(rhs)
296 }
297}
298
299macro_rules! impl_shl_scalar {
300 ($Rhs:ident) => {
301 impl Shl<$Rhs> for u8x16 {
302 type Output = Self;
303
304 #[inline]
310 fn shl(self, rhs: $Rhs) -> Self::Output {
311 pick! {
315 if #[cfg(target_feature="simd128")] {
316 Self { simd: u8x16_shl(self.simd, rhs as u32 & 7) }
318 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
319 unsafe { Self { neon: vshlq_u8(self.neon, vmovq_n_s8(rhs as i8 & 7)) } }
321 } else {
322 let self_array = self.to_array();
323 let rhs = rhs as u32;
324
325 cast([
326 self_array[0].wrapping_shl(rhs),
327 self_array[1].wrapping_shl(rhs),
328 self_array[2].wrapping_shl(rhs),
329 self_array[3].wrapping_shl(rhs),
330 self_array[4].wrapping_shl(rhs),
331 self_array[5].wrapping_shl(rhs),
332 self_array[6].wrapping_shl(rhs),
333 self_array[7].wrapping_shl(rhs),
334 self_array[8].wrapping_shl(rhs),
335 self_array[9].wrapping_shl(rhs),
336 self_array[10].wrapping_shl(rhs),
337 self_array[11].wrapping_shl(rhs),
338 self_array[12].wrapping_shl(rhs),
339 self_array[13].wrapping_shl(rhs),
340 self_array[14].wrapping_shl(rhs),
341 self_array[15].wrapping_shl(rhs),
342 ])
343 }
344 }
345 }
346 }
347 };
348}
349impl_shl_scalar!(i8);
350impl_shl_scalar!(u8);
351impl_shl_scalar!(i16);
352impl_shl_scalar!(u16);
353impl_shl_scalar!(i32);
354impl_shl_scalar!(u32);
355impl_shl_scalar!(i64);
356impl_shl_scalar!(u64);
357impl_shl_scalar!(i128);
358impl_shl_scalar!(u128);
359
360macro_rules! impl_shr_scalar {
361 ($Rhs:ident) => {
362 impl Shr<$Rhs> for u8x16 {
363 type Output = Self;
364
365 #[inline]
371 fn shr(self, rhs: $Rhs) -> Self::Output {
372 pick! {
376 if #[cfg(target_feature="simd128")] {
377 Self { simd: u8x16_shr(self.simd, rhs as u32 & 7) }
379 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
380 unsafe { Self { neon: vshlq_u8(self.neon, vmovq_n_s8(-(rhs as i8 & 7))) } }
383 } else {
384 let self_array = self.to_array();
385 let rhs = rhs as u32;
386
387 cast([
388 self_array[0].wrapping_shr(rhs),
389 self_array[1].wrapping_shr(rhs),
390 self_array[2].wrapping_shr(rhs),
391 self_array[3].wrapping_shr(rhs),
392 self_array[4].wrapping_shr(rhs),
393 self_array[5].wrapping_shr(rhs),
394 self_array[6].wrapping_shr(rhs),
395 self_array[7].wrapping_shr(rhs),
396 self_array[8].wrapping_shr(rhs),
397 self_array[9].wrapping_shr(rhs),
398 self_array[10].wrapping_shr(rhs),
399 self_array[11].wrapping_shr(rhs),
400 self_array[12].wrapping_shr(rhs),
401 self_array[13].wrapping_shr(rhs),
402 self_array[14].wrapping_shr(rhs),
403 self_array[15].wrapping_shr(rhs),
404 ])
405 }
406 }
407 }
408 }
409 };
410}
411impl_shr_scalar!(i8);
412impl_shr_scalar!(u8);
413impl_shr_scalar!(i16);
414impl_shr_scalar!(u16);
415impl_shr_scalar!(i32);
416impl_shr_scalar!(u32);
417impl_shr_scalar!(i64);
418impl_shr_scalar!(u64);
419impl_shr_scalar!(i128);
420impl_shr_scalar!(u128);
421
422impl Add<u8x16> for u8 {
423 type Output = u8x16;
424 #[inline]
425 fn add(self, rhs: u8x16) -> Self::Output {
426 u8x16::splat(self).add(rhs)
427 }
428}
429
430impl Sub<u8x16> for u8 {
431 type Output = u8x16;
432 #[inline]
433 fn sub(self, rhs: u8x16) -> Self::Output {
434 u8x16::splat(self).sub(rhs)
435 }
436}
437
438impl Mul<u8x16> for u8 {
439 type Output = u8x16;
440
441 #[inline]
442 fn mul(self, rhs: u8x16) -> Self::Output {
443 u8x16::splat(self) * rhs
444 }
445}
446
447impl BitAnd for u8x16 {
448 type Output = Self;
449 #[inline]
450 fn bitand(self, rhs: Self) -> Self::Output {
451 pick! {
452 if #[cfg(target_feature="sse2")] {
453 Self { sse: bitand_m128i(self.sse, rhs.sse) }
454 } else if #[cfg(target_feature="simd128")] {
455 Self { simd: v128_and(self.simd, rhs.simd) }
456 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
457 unsafe {Self { neon: vandq_u8(self.neon, rhs.neon) }}
458 } else {
459 Self { arr: [
460 self.arr[0].bitand(rhs.arr[0]),
461 self.arr[1].bitand(rhs.arr[1]),
462 self.arr[2].bitand(rhs.arr[2]),
463 self.arr[3].bitand(rhs.arr[3]),
464 self.arr[4].bitand(rhs.arr[4]),
465 self.arr[5].bitand(rhs.arr[5]),
466 self.arr[6].bitand(rhs.arr[6]),
467 self.arr[7].bitand(rhs.arr[7]),
468 self.arr[8].bitand(rhs.arr[8]),
469 self.arr[9].bitand(rhs.arr[9]),
470 self.arr[10].bitand(rhs.arr[10]),
471 self.arr[11].bitand(rhs.arr[11]),
472 self.arr[12].bitand(rhs.arr[12]),
473 self.arr[13].bitand(rhs.arr[13]),
474 self.arr[14].bitand(rhs.arr[14]),
475 self.arr[15].bitand(rhs.arr[15]),
476 ]}
477 }
478 }
479 }
480}
481
482impl BitOr for u8x16 {
483 type Output = Self;
484 #[inline]
485 fn bitor(self, rhs: Self) -> Self::Output {
486 pick! {
487 if #[cfg(target_feature="sse2")] {
488 Self { sse: bitor_m128i(self.sse, rhs.sse) }
489 } else if #[cfg(target_feature="simd128")] {
490 Self { simd: v128_or(self.simd, rhs.simd) }
491 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
492 unsafe {Self { neon: vorrq_u8(self.neon, rhs.neon) }}
493 } else {
494 Self { arr: [
495 self.arr[0].bitor(rhs.arr[0]),
496 self.arr[1].bitor(rhs.arr[1]),
497 self.arr[2].bitor(rhs.arr[2]),
498 self.arr[3].bitor(rhs.arr[3]),
499 self.arr[4].bitor(rhs.arr[4]),
500 self.arr[5].bitor(rhs.arr[5]),
501 self.arr[6].bitor(rhs.arr[6]),
502 self.arr[7].bitor(rhs.arr[7]),
503 self.arr[8].bitor(rhs.arr[8]),
504 self.arr[9].bitor(rhs.arr[9]),
505 self.arr[10].bitor(rhs.arr[10]),
506 self.arr[11].bitor(rhs.arr[11]),
507 self.arr[12].bitor(rhs.arr[12]),
508 self.arr[13].bitor(rhs.arr[13]),
509 self.arr[14].bitor(rhs.arr[14]),
510 self.arr[15].bitor(rhs.arr[15]),
511 ]}
512 }
513 }
514 }
515}
516
517impl BitXor for u8x16 {
518 type Output = Self;
519 #[inline]
520 fn bitxor(self, rhs: Self) -> Self::Output {
521 pick! {
522 if #[cfg(target_feature="sse2")] {
523 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
524 } else if #[cfg(target_feature="simd128")] {
525 Self { simd: v128_xor(self.simd, rhs.simd) }
526 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
527 unsafe {Self { neon: veorq_u8(self.neon, rhs.neon) }}
528 } else {
529 Self { arr: [
530 self.arr[0].bitxor(rhs.arr[0]),
531 self.arr[1].bitxor(rhs.arr[1]),
532 self.arr[2].bitxor(rhs.arr[2]),
533 self.arr[3].bitxor(rhs.arr[3]),
534 self.arr[4].bitxor(rhs.arr[4]),
535 self.arr[5].bitxor(rhs.arr[5]),
536 self.arr[6].bitxor(rhs.arr[6]),
537 self.arr[7].bitxor(rhs.arr[7]),
538 self.arr[8].bitxor(rhs.arr[8]),
539 self.arr[9].bitxor(rhs.arr[9]),
540 self.arr[10].bitxor(rhs.arr[10]),
541 self.arr[11].bitxor(rhs.arr[11]),
542 self.arr[12].bitxor(rhs.arr[12]),
543 self.arr[13].bitxor(rhs.arr[13]),
544 self.arr[14].bitxor(rhs.arr[14]),
545 self.arr[15].bitxor(rhs.arr[15]),
546 ]}
547 }
548 }
549 }
550}
551
552#[expect(deprecated)]
553impl CmpEq for u8x16 {
554 type Output = Self;
555 #[inline]
556 fn simd_eq(self, rhs: Self) -> Self::Output {
557 pick! {
558 if #[cfg(target_feature="sse2")] {
559 Self { sse: cmp_eq_mask_i8_m128i(self.sse, rhs.sse) }
560 } else if #[cfg(target_feature="simd128")] {
561 Self { simd: u8x16_eq(self.simd, rhs.simd) }
562 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
563 unsafe {Self { neon: vceqq_u8(self.neon, rhs.neon) }}
564 } else {
565 Self { arr: [
566 if self.arr[0] == rhs.arr[0] { u8::MAX } else { 0 },
567 if self.arr[1] == rhs.arr[1] { u8::MAX } else { 0 },
568 if self.arr[2] == rhs.arr[2] { u8::MAX } else { 0 },
569 if self.arr[3] == rhs.arr[3] { u8::MAX } else { 0 },
570 if self.arr[4] == rhs.arr[4] { u8::MAX } else { 0 },
571 if self.arr[5] == rhs.arr[5] { u8::MAX } else { 0 },
572 if self.arr[6] == rhs.arr[6] { u8::MAX } else { 0 },
573 if self.arr[7] == rhs.arr[7] { u8::MAX } else { 0 },
574 if self.arr[8] == rhs.arr[8] { u8::MAX } else { 0 },
575 if self.arr[9] == rhs.arr[9] { u8::MAX } else { 0 },
576 if self.arr[10] == rhs.arr[10] { u8::MAX } else { 0 },
577 if self.arr[11] == rhs.arr[11] { u8::MAX } else { 0 },
578 if self.arr[12] == rhs.arr[12] { u8::MAX } else { 0 },
579 if self.arr[13] == rhs.arr[13] { u8::MAX } else { 0 },
580 if self.arr[14] == rhs.arr[14] { u8::MAX } else { 0 },
581 if self.arr[15] == rhs.arr[15] { u8::MAX } else { 0 },
582 ]}
583 }
584 }
585 }
586}
587
588#[expect(deprecated)]
589impl CmpNe for u8x16 {
590 type Output = Self;
591 #[inline]
592 fn simd_ne(self, rhs: Self) -> Self::Output {
593 pick! {
594 if #[cfg(target_feature="sse2")] {
595 !self.simd_eq(rhs)
596 } else if #[cfg(target_feature="simd128")] {
597 Self { simd: u8x16_ne(self.simd, rhs.simd) }
598 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
599 !self.simd_eq(rhs)
600 } else {
601 Self { arr: [
602 if self.arr[0] != rhs.arr[0] { u8::MAX } else { 0 },
603 if self.arr[1] != rhs.arr[1] { u8::MAX } else { 0 },
604 if self.arr[2] != rhs.arr[2] { u8::MAX } else { 0 },
605 if self.arr[3] != rhs.arr[3] { u8::MAX } else { 0 },
606 if self.arr[4] != rhs.arr[4] { u8::MAX } else { 0 },
607 if self.arr[5] != rhs.arr[5] { u8::MAX } else { 0 },
608 if self.arr[6] != rhs.arr[6] { u8::MAX } else { 0 },
609 if self.arr[7] != rhs.arr[7] { u8::MAX } else { 0 },
610 if self.arr[8] != rhs.arr[8] { u8::MAX } else { 0 },
611 if self.arr[9] != rhs.arr[9] { u8::MAX } else { 0 },
612 if self.arr[10] != rhs.arr[10] { u8::MAX } else { 0 },
613 if self.arr[11] != rhs.arr[11] { u8::MAX } else { 0 },
614 if self.arr[12] != rhs.arr[12] { u8::MAX } else { 0 },
615 if self.arr[13] != rhs.arr[13] { u8::MAX } else { 0 },
616 if self.arr[14] != rhs.arr[14] { u8::MAX } else { 0 },
617 if self.arr[15] != rhs.arr[15] { u8::MAX } else { 0 },
618 ]}
619 }
620 }
621 }
622}
623
624#[expect(deprecated)]
625impl CmpLt for u8x16 {
626 type Output = Self;
627 #[inline]
628 fn simd_lt(self, rhs: Self) -> Self::Output {
629 pick! {
630 if #[cfg(target_feature="sse2")] {
631 let offset = Self::splat(0x80);
633 let self_i8 = self.bitxor(offset).sse;
634 let rhs_i8 = rhs.bitxor(offset).sse;
635 Self { sse: cmp_lt_mask_i8_m128i(self_i8, rhs_i8) }
636 } else if #[cfg(target_feature="simd128")] {
637 Self { simd: u8x16_lt(self.simd, rhs.simd) }
638 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
639 unsafe {Self { neon: vcltq_u8(self.neon, rhs.neon) }}
640 } else {
641 Self { arr: [
642 if self.arr[0] < rhs.arr[0] { u8::MAX } else { 0 },
643 if self.arr[1] < rhs.arr[1] { u8::MAX } else { 0 },
644 if self.arr[2] < rhs.arr[2] { u8::MAX } else { 0 },
645 if self.arr[3] < rhs.arr[3] { u8::MAX } else { 0 },
646 if self.arr[4] < rhs.arr[4] { u8::MAX } else { 0 },
647 if self.arr[5] < rhs.arr[5] { u8::MAX } else { 0 },
648 if self.arr[6] < rhs.arr[6] { u8::MAX } else { 0 },
649 if self.arr[7] < rhs.arr[7] { u8::MAX } else { 0 },
650 if self.arr[8] < rhs.arr[8] { u8::MAX } else { 0 },
651 if self.arr[9] < rhs.arr[9] { u8::MAX } else { 0 },
652 if self.arr[10] < rhs.arr[10] { u8::MAX } else { 0 },
653 if self.arr[11] < rhs.arr[11] { u8::MAX } else { 0 },
654 if self.arr[12] < rhs.arr[12] { u8::MAX } else { 0 },
655 if self.arr[13] < rhs.arr[13] { u8::MAX } else { 0 },
656 if self.arr[14] < rhs.arr[14] { u8::MAX } else { 0 },
657 if self.arr[15] < rhs.arr[15] { u8::MAX } else { 0 },
658 ]}
659 }
660 }
661 }
662}
663
664#[expect(deprecated)]
665impl CmpLe for u8x16 {
666 type Output = Self;
667 #[inline]
668 fn simd_le(self, rhs: Self) -> Self::Output {
669 pick! {
670 if #[cfg(target_feature="sse2")] {
671 let offset = Self::splat(0x80);
673 let self_i8 = self.bitxor(offset).sse;
674 let rhs_i8 = rhs.bitxor(offset).sse;
675 let gt_mask = u8x16 { sse: cmp_gt_mask_i8_m128i(self_i8, rhs_i8) };
677 Self { sse: gt_mask.bitxor(u8x16::splat(0xFF)).sse }
678 } else if #[cfg(target_feature="simd128")] {
679 Self { simd: u8x16_le(self.simd, rhs.simd) }
680 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
681 unsafe {Self { neon: vcleq_u8(self.neon, rhs.neon) }}
682 } else {
683 Self { arr: [
684 if self.arr[0] <= rhs.arr[0] { u8::MAX } else { 0 },
685 if self.arr[1] <= rhs.arr[1] { u8::MAX } else { 0 },
686 if self.arr[2] <= rhs.arr[2] { u8::MAX } else { 0 },
687 if self.arr[3] <= rhs.arr[3] { u8::MAX } else { 0 },
688 if self.arr[4] <= rhs.arr[4] { u8::MAX } else { 0 },
689 if self.arr[5] <= rhs.arr[5] { u8::MAX } else { 0 },
690 if self.arr[6] <= rhs.arr[6] { u8::MAX } else { 0 },
691 if self.arr[7] <= rhs.arr[7] { u8::MAX } else { 0 },
692 if self.arr[8] <= rhs.arr[8] { u8::MAX } else { 0 },
693 if self.arr[9] <= rhs.arr[9] { u8::MAX } else { 0 },
694 if self.arr[10] <= rhs.arr[10] { u8::MAX } else { 0 },
695 if self.arr[11] <= rhs.arr[11] { u8::MAX } else { 0 },
696 if self.arr[12] <= rhs.arr[12] { u8::MAX } else { 0 },
697 if self.arr[13] <= rhs.arr[13] { u8::MAX } else { 0 },
698 if self.arr[14] <= rhs.arr[14] { u8::MAX } else { 0 },
699 if self.arr[15] <= rhs.arr[15] { u8::MAX } else { 0 },
700 ]}
701 }
702 }
703 }
704}
705
706#[expect(deprecated)]
707impl CmpGe for u8x16 {
708 type Output = Self;
709 #[inline]
710 fn simd_ge(self, rhs: Self) -> Self::Output {
711 pick! {
712 if #[cfg(target_feature="sse2")] {
713 let offset = Self::splat(0x80);
715 let self_i8 = self.bitxor(offset).sse;
716 let rhs_i8 = rhs.bitxor(offset).sse;
717 let lt_mask = u8x16 { sse: cmp_lt_mask_i8_m128i(self_i8, rhs_i8) };
719 Self { sse: lt_mask.bitxor(u8x16::splat(0xFF)).sse }
720 } else if #[cfg(target_feature="simd128")] {
721 Self { simd: u8x16_ge(self.simd, rhs.simd) }
722 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
723 unsafe {Self { neon: vcgeq_u8(self.neon, rhs.neon) }}
724 } else {
725 Self { arr: [
726 if self.arr[0] >= rhs.arr[0] { u8::MAX } else { 0 },
727 if self.arr[1] >= rhs.arr[1] { u8::MAX } else { 0 },
728 if self.arr[2] >= rhs.arr[2] { u8::MAX } else { 0 },
729 if self.arr[3] >= rhs.arr[3] { u8::MAX } else { 0 },
730 if self.arr[4] >= rhs.arr[4] { u8::MAX } else { 0 },
731 if self.arr[5] >= rhs.arr[5] { u8::MAX } else { 0 },
732 if self.arr[6] >= rhs.arr[6] { u8::MAX } else { 0 },
733 if self.arr[7] >= rhs.arr[7] { u8::MAX } else { 0 },
734 if self.arr[8] >= rhs.arr[8] { u8::MAX } else { 0 },
735 if self.arr[9] >= rhs.arr[9] { u8::MAX } else { 0 },
736 if self.arr[10] >= rhs.arr[10] { u8::MAX } else { 0 },
737 if self.arr[11] >= rhs.arr[11] { u8::MAX } else { 0 },
738 if self.arr[12] >= rhs.arr[12] { u8::MAX } else { 0 },
739 if self.arr[13] >= rhs.arr[13] { u8::MAX } else { 0 },
740 if self.arr[14] >= rhs.arr[14] { u8::MAX } else { 0 },
741 if self.arr[15] >= rhs.arr[15] { u8::MAX } else { 0 },
742 ]}
743 }
744 }
745 }
746}
747
748#[expect(deprecated)]
749impl CmpGt for u8x16 {
750 type Output = Self;
751 #[inline]
752 fn simd_gt(self, rhs: Self) -> Self::Output {
753 pick! {
754 if #[cfg(target_feature="sse2")] {
755 let offset = Self::splat(0x80);
757 let self_i8 = self.bitxor(offset).sse;
758 let rhs_i8 = rhs.bitxor(offset).sse;
759 Self { sse: cmp_gt_mask_i8_m128i(self_i8, rhs_i8) }
760 } else if #[cfg(target_feature="simd128")] {
761 Self { simd: u8x16_gt(self.simd, rhs.simd) }
762 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
763 unsafe {Self { neon: vcgtq_u8(self.neon, rhs.neon) }}
764 } else {
765 Self { arr: [
766 if self.arr[0] > rhs.arr[0] { u8::MAX } else { 0 },
767 if self.arr[1] > rhs.arr[1] { u8::MAX } else { 0 },
768 if self.arr[2] > rhs.arr[2] { u8::MAX } else { 0 },
769 if self.arr[3] > rhs.arr[3] { u8::MAX } else { 0 },
770 if self.arr[4] > rhs.arr[4] { u8::MAX } else { 0 },
771 if self.arr[5] > rhs.arr[5] { u8::MAX } else { 0 },
772 if self.arr[6] > rhs.arr[6] { u8::MAX } else { 0 },
773 if self.arr[7] > rhs.arr[7] { u8::MAX } else { 0 },
774 if self.arr[8] > rhs.arr[8] { u8::MAX } else { 0 },
775 if self.arr[9] > rhs.arr[9] { u8::MAX } else { 0 },
776 if self.arr[10] > rhs.arr[10] { u8::MAX } else { 0 },
777 if self.arr[11] > rhs.arr[11] { u8::MAX } else { 0 },
778 if self.arr[12] > rhs.arr[12] { u8::MAX } else { 0 },
779 if self.arr[13] > rhs.arr[13] { u8::MAX } else { 0 },
780 if self.arr[14] > rhs.arr[14] { u8::MAX } else { 0 },
781 if self.arr[15] > rhs.arr[15] { u8::MAX } else { 0 },
782 ]}
783 }
784 }
785 }
786}
787
788impl u8x16 {
789 #[inline]
790 #[must_use]
791 pub const fn new(array: [u8; 16]) -> Self {
792 unsafe { core::mem::transmute(array) }
793 }
794
795 simd_comparison_fns!();
796
797 #[inline]
798 #[must_use]
799 pub fn blend(self, t: Self, f: Self) -> Self {
800 pick! {
801 if #[cfg(target_feature="sse4.1")] {
802 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
803 } else if #[cfg(target_feature="simd128")] {
804 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
805 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
806 unsafe {Self { neon: vbslq_u8(self.neon, t.neon, f.neon) }}
807 } else {
808 generic_bit_blend(self, t, f)
809 }
810 }
811 }
812
813 #[inline]
814 #[must_use]
815 pub fn reduce_add(self) -> u8 {
816 cast(i8x16::reduce_add(cast(self)))
817 }
818
819 #[inline]
820 #[must_use]
821 pub fn reduce_max(self) -> u8 {
822 #[allow(dead_code)]
823 const SHUFFLE_1: [i8; 16] =
824 [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
825 #[allow(dead_code)]
826 const SHUFFLE_2: [i8; 16] =
827 [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
828 #[allow(dead_code)]
829 const SHUFFLE_3: [i8; 16] =
830 [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
831 #[allow(dead_code)]
832 const SHUFFLE_4: [i8; 16] =
833 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
834
835 pick! {
836 if #[cfg(target_feature="ssse3")] {
837 let rhs = shuffle_av_i8z_all_m128i(self.sse, m128i::from(SHUFFLE_1));
838 let max = max_u8_m128i(self.sse, rhs);
839 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_2));
840 let max = max_u8_m128i(max, rhs);
841 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_3));
842 let max = max_u8_m128i(max, rhs);
843 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_4));
844 let max = max_u8_m128i(max, rhs);
845 get_i32_from_m128i_s(max) as u8
846 } else if #[cfg(target_feature="simd128")] {
847 let rhs = u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7>(self.simd, self.simd);
848 let max = u8x16_max(self.simd, rhs);
849 let rhs = u8x16_shuffle::<4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
850 let max = u8x16_max(max, rhs);
851 let rhs = u8x16_shuffle::<2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
852 let max = u8x16_max(max, rhs);
853 let rhs = u8x16_shuffle::<1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
854 let max = u8x16_max(max, rhs);
855 u8x16_extract_lane::<0>(max)
856 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
857 unsafe {
858 let rhs = vqtbl1q_u8(self.neon, core::mem::transmute(SHUFFLE_1));
861 let max = vmaxq_u8(self.neon, rhs);
862 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_2));
863 let max = vmaxq_u8(max, rhs);
864 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_3));
865 let max = vmaxq_u8(max, rhs);
866 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_4));
867 let max = vmaxq_u8(max, rhs);
868 vgetq_lane_u8(max, 0)
869 }
870 } else {
871 let array: [u8; 16] = cast(self);
872 array.into_iter().reduce(u8::max).unwrap()
873 }
874 }
875 }
876
877 #[inline]
878 #[must_use]
879 pub fn reduce_min(self) -> u8 {
880 #[allow(dead_code)]
881 const SHUFFLE_1: [i8; 16] =
882 [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
883 #[allow(dead_code)]
884 const SHUFFLE_2: [i8; 16] =
885 [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
886 #[allow(dead_code)]
887 const SHUFFLE_3: [i8; 16] =
888 [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
889 #[allow(dead_code)]
890 const SHUFFLE_4: [i8; 16] =
891 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
892
893 pick! {
894 if #[cfg(target_feature="ssse3")] {
895 let rhs = shuffle_av_i8z_all_m128i(self.sse, m128i::from(SHUFFLE_1));
896 let min = min_u8_m128i(self.sse, rhs);
897 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_2));
898 let min = min_u8_m128i(min, rhs);
899 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_3));
900 let min = min_u8_m128i(min, rhs);
901 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_4));
902 let min = min_u8_m128i(min, rhs);
903 get_i32_from_m128i_s(min) as u8
904 } else if #[cfg(target_feature="simd128")] {
905 let rhs = u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7>(self.simd, self.simd);
906 let min = u8x16_min(self.simd, rhs);
907 let rhs = u8x16_shuffle::<4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
908 let min = u8x16_min(min, rhs);
909 let rhs = u8x16_shuffle::<2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
910 let min = u8x16_min(min, rhs);
911 let rhs = u8x16_shuffle::<1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
912 let min = u8x16_min(min, rhs);
913 u8x16_extract_lane::<0>(min)
914 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
915 unsafe {
916 let rhs = vqtbl1q_u8(self.neon, core::mem::transmute(SHUFFLE_1));
919 let min = vminq_u8(self.neon, rhs);
920 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_2));
921 let min = vminq_u8(min, rhs);
922 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_3));
923 let min = vminq_u8(min, rhs);
924 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_4));
925 let min = vminq_u8(min, rhs);
926 vgetq_lane_u8(min, 0)
927 }
928 } else {
929 let array: [u8; 16] = cast(self);
930 array.into_iter().reduce(u8::min).unwrap()
931 }
932 }
933 }
934
935 #[inline]
936 #[must_use]
937 pub fn max(self, rhs: Self) -> Self {
938 pick! {
939 if #[cfg(target_feature="sse2")] {
940 Self { sse: max_u8_m128i(self.sse, rhs.sse) }
941 } else if #[cfg(target_feature="simd128")] {
942 Self { simd: u8x16_max(self.simd, rhs.simd) }
943 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
944 unsafe {Self { neon: vmaxq_u8(self.neon, rhs.neon) }}
945 } else {
946 Self { arr: [
947 self.arr[0].max(rhs.arr[0]),
948 self.arr[1].max(rhs.arr[1]),
949 self.arr[2].max(rhs.arr[2]),
950 self.arr[3].max(rhs.arr[3]),
951 self.arr[4].max(rhs.arr[4]),
952 self.arr[5].max(rhs.arr[5]),
953 self.arr[6].max(rhs.arr[6]),
954 self.arr[7].max(rhs.arr[7]),
955 self.arr[8].max(rhs.arr[8]),
956 self.arr[9].max(rhs.arr[9]),
957 self.arr[10].max(rhs.arr[10]),
958 self.arr[11].max(rhs.arr[11]),
959 self.arr[12].max(rhs.arr[12]),
960 self.arr[13].max(rhs.arr[13]),
961 self.arr[14].max(rhs.arr[14]),
962 self.arr[15].max(rhs.arr[15]),
963 ]}
964 }
965 }
966 }
967 #[inline]
968 #[must_use]
969 pub fn min(self, rhs: Self) -> Self {
970 pick! {
971 if #[cfg(target_feature="sse2")] {
972 Self { sse: min_u8_m128i(self.sse, rhs.sse) }
973 } else if #[cfg(target_feature="simd128")] {
974 Self { simd: u8x16_min(self.simd, rhs.simd) }
975 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
976 unsafe {Self { neon: vminq_u8(self.neon, rhs.neon) }}
977 } else {
978 Self { arr: [
979 self.arr[0].min(rhs.arr[0]),
980 self.arr[1].min(rhs.arr[1]),
981 self.arr[2].min(rhs.arr[2]),
982 self.arr[3].min(rhs.arr[3]),
983 self.arr[4].min(rhs.arr[4]),
984 self.arr[5].min(rhs.arr[5]),
985 self.arr[6].min(rhs.arr[6]),
986 self.arr[7].min(rhs.arr[7]),
987 self.arr[8].min(rhs.arr[8]),
988 self.arr[9].min(rhs.arr[9]),
989 self.arr[10].min(rhs.arr[10]),
990 self.arr[11].min(rhs.arr[11]),
991 self.arr[12].min(rhs.arr[12]),
992 self.arr[13].min(rhs.arr[13]),
993 self.arr[14].min(rhs.arr[14]),
994 self.arr[15].min(rhs.arr[15]),
995 ]}
996 }
997 }
998 }
999
1000 integer_fn_clamp!();
1001
1002 #[inline]
1003 #[must_use]
1004 pub fn saturating_add(self, rhs: Self) -> Self {
1005 pick! {
1006 if #[cfg(target_feature="sse2")] {
1007 Self { sse: add_saturating_u8_m128i(self.sse, rhs.sse) }
1008 } else if #[cfg(target_feature="simd128")] {
1009 Self { simd: u8x16_add_sat(self.simd, rhs.simd) }
1010 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1011 unsafe {Self { neon: vqaddq_u8(self.neon, rhs.neon) }}
1012 } else {
1013 Self { arr: [
1014 self.arr[0].saturating_add(rhs.arr[0]),
1015 self.arr[1].saturating_add(rhs.arr[1]),
1016 self.arr[2].saturating_add(rhs.arr[2]),
1017 self.arr[3].saturating_add(rhs.arr[3]),
1018 self.arr[4].saturating_add(rhs.arr[4]),
1019 self.arr[5].saturating_add(rhs.arr[5]),
1020 self.arr[6].saturating_add(rhs.arr[6]),
1021 self.arr[7].saturating_add(rhs.arr[7]),
1022 self.arr[8].saturating_add(rhs.arr[8]),
1023 self.arr[9].saturating_add(rhs.arr[9]),
1024 self.arr[10].saturating_add(rhs.arr[10]),
1025 self.arr[11].saturating_add(rhs.arr[11]),
1026 self.arr[12].saturating_add(rhs.arr[12]),
1027 self.arr[13].saturating_add(rhs.arr[13]),
1028 self.arr[14].saturating_add(rhs.arr[14]),
1029 self.arr[15].saturating_add(rhs.arr[15]),
1030 ]}
1031 }
1032 }
1033 }
1034 #[inline]
1035 #[must_use]
1036 pub fn saturating_sub(self, rhs: Self) -> Self {
1037 pick! {
1038 if #[cfg(target_feature="sse2")] {
1039 Self { sse: sub_saturating_u8_m128i(self.sse, rhs.sse) }
1040 } else if #[cfg(target_feature="simd128")] {
1041 Self { simd: u8x16_sub_sat(self.simd, rhs.simd) }
1042 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1043 unsafe { Self { neon: vqsubq_u8(self.neon, rhs.neon) } }
1044 } else {
1045 Self { arr: [
1046 self.arr[0].saturating_sub(rhs.arr[0]),
1047 self.arr[1].saturating_sub(rhs.arr[1]),
1048 self.arr[2].saturating_sub(rhs.arr[2]),
1049 self.arr[3].saturating_sub(rhs.arr[3]),
1050 self.arr[4].saturating_sub(rhs.arr[4]),
1051 self.arr[5].saturating_sub(rhs.arr[5]),
1052 self.arr[6].saturating_sub(rhs.arr[6]),
1053 self.arr[7].saturating_sub(rhs.arr[7]),
1054 self.arr[8].saturating_sub(rhs.arr[8]),
1055 self.arr[9].saturating_sub(rhs.arr[9]),
1056 self.arr[10].saturating_sub(rhs.arr[10]),
1057 self.arr[11].saturating_sub(rhs.arr[11]),
1058 self.arr[12].saturating_sub(rhs.arr[12]),
1059 self.arr[13].saturating_sub(rhs.arr[13]),
1060 self.arr[14].saturating_sub(rhs.arr[14]),
1061 self.arr[15].saturating_sub(rhs.arr[15]),
1062 ]}
1063 }
1064 }
1065 }
1066
1067 #[inline]
1069 #[must_use]
1070 pub fn saturating_mul(self, rhs: Self) -> Self {
1071 pick! {
1072 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1073 unsafe {
1074 let low_wide_mul = vreinterpretq_u8_u16(
1075 vmull_u8(vget_low_u8(self.neon), vget_low_u8(rhs.neon)),
1076 );
1077 let high_wide_mul = vreinterpretq_u8_u16(
1078 vmull_u8(vget_high_u8(self.neon), vget_high_u8(rhs.neon)),
1079 );
1080 let low_high = vuzpq_u8(low_wide_mul, high_wide_mul);
1081 let low = Self { neon: low_high.0 };
1082 let high = Self { neon: low_high.1 };
1083
1084 let no_overflow = high.simd_eq(Self::ZERO);
1085 no_overflow.blend(low, Self::MAX)
1086 }
1087 } else {
1088 let self_array = self.to_array();
1089 let rhs_array = rhs.to_array();
1090
1091 Self::new([
1092 self_array[0].saturating_mul(rhs_array[0]),
1093 self_array[1].saturating_mul(rhs_array[1]),
1094 self_array[2].saturating_mul(rhs_array[2]),
1095 self_array[3].saturating_mul(rhs_array[3]),
1096 self_array[4].saturating_mul(rhs_array[4]),
1097 self_array[5].saturating_mul(rhs_array[5]),
1098 self_array[6].saturating_mul(rhs_array[6]),
1099 self_array[7].saturating_mul(rhs_array[7]),
1100 self_array[8].saturating_mul(rhs_array[8]),
1101 self_array[9].saturating_mul(rhs_array[9]),
1102 self_array[10].saturating_mul(rhs_array[10]),
1103 self_array[11].saturating_mul(rhs_array[11]),
1104 self_array[12].saturating_mul(rhs_array[12]),
1105 self_array[13].saturating_mul(rhs_array[13]),
1106 self_array[14].saturating_mul(rhs_array[14]),
1107 self_array[15].saturating_mul(rhs_array[15]),
1108 ])
1109 }
1110 }
1111 }
1112
1113 integer_fn_saturating_div!([
1114 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
1115 ]);
1116
1117 #[inline]
1119 #[must_use]
1120 pub fn unpack_low(lhs: u8x16, rhs: u8x16) -> u8x16 {
1121 pick! {
1122 if #[cfg(target_feature = "sse2")] {
1123 u8x16 { sse: unpack_low_i8_m128i(lhs.sse, rhs.sse) }
1124 } else if #[cfg(target_feature = "simd128")] {
1125 u8x16 { simd: u8x16_shuffle::<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23>(lhs.simd, rhs.simd) }
1126 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1127 let lhs = unsafe { vget_low_u8(lhs.neon) };
1128 let rhs = unsafe { vget_low_u8(rhs.neon) };
1129
1130 let zipped = unsafe { vzip_u8(lhs, rhs) };
1131 u8x16 { neon: unsafe { vcombine_u8(zipped.0, zipped.1) } }
1132 } else {
1133 u8x16::new([
1134 lhs.as_array()[0], rhs.as_array()[0],
1135 lhs.as_array()[1], rhs.as_array()[1],
1136 lhs.as_array()[2], rhs.as_array()[2],
1137 lhs.as_array()[3], rhs.as_array()[3],
1138 lhs.as_array()[4], rhs.as_array()[4],
1139 lhs.as_array()[5], rhs.as_array()[5],
1140 lhs.as_array()[6], rhs.as_array()[6],
1141 lhs.as_array()[7], rhs.as_array()[7],
1142 ])
1143 }
1144 }
1145 }
1146
1147 #[inline]
1149 #[must_use]
1150 pub fn unpack_high(lhs: u8x16, rhs: u8x16) -> u8x16 {
1151 pick! {
1152 if #[cfg(target_feature = "sse2")] {
1153 u8x16 { sse: unpack_high_i8_m128i(lhs.sse, rhs.sse) }
1154 } else if #[cfg(target_feature = "simd128")] {
1155 u8x16 { simd: u8x16_shuffle::<8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31>(lhs.simd, rhs.simd) }
1156 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1157 let lhs = unsafe { vget_high_u8(lhs.neon) };
1158 let rhs = unsafe { vget_high_u8(rhs.neon) };
1159
1160 let zipped = unsafe { vzip_u8(lhs, rhs) };
1161 u8x16 { neon: unsafe { vcombine_u8(zipped.0, zipped.1) } }
1162 } else {
1163 u8x16::new([
1164 lhs.as_array()[8], rhs.as_array()[8],
1165 lhs.as_array()[9], rhs.as_array()[9],
1166 lhs.as_array()[10], rhs.as_array()[10],
1167 lhs.as_array()[11], rhs.as_array()[11],
1168 lhs.as_array()[12], rhs.as_array()[12],
1169 lhs.as_array()[13], rhs.as_array()[13],
1170 lhs.as_array()[14], rhs.as_array()[14],
1171 lhs.as_array()[15], rhs.as_array()[15],
1172 ])
1173 }
1174 }
1175 }
1176
1177 #[inline]
1179 #[must_use]
1180 pub fn narrow_i16x8(lhs: i16x8, rhs: i16x8) -> Self {
1181 pick! {
1182 if #[cfg(target_feature = "sse2")] {
1183 u8x16 { sse: pack_i16_to_u8_m128i(lhs.sse, rhs.sse) }
1184 } else if #[cfg(target_feature = "simd128")] {
1185 u8x16 { simd: u8x16_narrow_i16x8(lhs.simd, rhs.simd) }
1186 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1187 let lhs = unsafe { vqmovun_s16(lhs.neon) };
1188 let rhs = unsafe { vqmovun_s16(rhs.neon) };
1189 u8x16 { neon: unsafe { vcombine_u8(lhs, rhs) } }
1190 } else {
1191 fn clamp(a: i16) -> u8 {
1192 if a < u8::MIN as i16 {
1193 u8::MIN
1194 } else if a > u8::MAX as i16 {
1195 u8::MAX
1196 } else {
1197 a as u8
1198 }
1199 }
1200
1201 Self { arr: [
1202 clamp(lhs.as_array()[0]),
1203 clamp(lhs.as_array()[1]),
1204 clamp(lhs.as_array()[2]),
1205 clamp(lhs.as_array()[3]),
1206 clamp(lhs.as_array()[4]),
1207 clamp(lhs.as_array()[5]),
1208 clamp(lhs.as_array()[6]),
1209 clamp(lhs.as_array()[7]),
1210 clamp(rhs.as_array()[0]),
1211 clamp(rhs.as_array()[1]),
1212 clamp(rhs.as_array()[2]),
1213 clamp(rhs.as_array()[3]),
1214 clamp(rhs.as_array()[4]),
1215 clamp(rhs.as_array()[5]),
1216 clamp(rhs.as_array()[6]),
1217 clamp(rhs.as_array()[7]),
1218 ]}
1219 }
1220 }
1221 }
1222
1223 #[inline]
1230 pub fn swizzle(self, rhs: i8x16) -> i8x16 {
1231 cast(i8x16::swizzle(cast(self), rhs))
1232 }
1233
1234 #[inline]
1243 pub fn swizzle_relaxed(self, rhs: u8x16) -> u8x16 {
1244 cast(i8x16::swizzle_relaxed(cast(self), cast(rhs)))
1245 }
1246
1247 #[inline]
1248 #[must_use]
1249 #[doc(alias("movemask", "move_mask"))]
1250 pub fn to_bitmask(self) -> u32 {
1251 i8x16::to_bitmask(cast(self)) as u32
1252 }
1253
1254 #[inline]
1255 #[must_use]
1256 pub fn any(self) -> bool {
1257 i8x16::any(cast(self))
1258 }
1259
1260 #[inline]
1261 #[must_use]
1262 pub fn all(self) -> bool {
1263 i8x16::all(cast(self))
1264 }
1265
1266 #[inline]
1267 #[must_use]
1268 pub fn none(self) -> bool {
1269 i8x16::none(cast(self))
1270 }
1271
1272 #[must_use]
1274 #[inline]
1275 pub fn transpose(data: [u8x16; 16]) -> [u8x16; 16] {
1276 cast(i8x16::transpose(cast(data)))
1277 }
1278
1279 #[inline]
1280 pub fn to_array(self) -> [u8; 16] {
1281 cast(self)
1282 }
1283
1284 #[inline]
1285 pub fn as_array(&self) -> &[u8; 16] {
1286 cast_ref(self)
1287 }
1288
1289 #[inline]
1290 pub fn as_mut_array(&mut self) -> &mut [u8; 16] {
1291 cast_mut(self)
1292 }
1293}