1use super::*;
2
3pick! {
4 if #[cfg(target_feature="sse2")] {
5 #[derive(Default, Clone, Copy, PartialEq, Eq)]
12 #[repr(C, align(16))]
13 pub struct u8x16 { pub(crate) sse: m128i }
14 } else if #[cfg(target_feature="simd128")] {
15 use core::arch::wasm32::*;
16
17 #[derive(Clone, Copy)]
24 #[repr(transparent)]
25 pub struct u8x16 { pub(crate) simd: v128 }
26
27 impl Default for u8x16 {
28 fn default() -> Self {
29 Self::splat(0)
30 }
31 }
32
33 impl PartialEq for u8x16 {
34 fn eq(&self, other: &Self) -> bool {
35 u8x16_all_true(u8x16_eq(self.simd, other.simd))
36 }
37 }
38
39 impl Eq for u8x16 { }
40 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
41 use core::arch::aarch64::*;
42
43 #[repr(C)]
50 #[derive(Copy, Clone)]
51 pub struct u8x16 { pub(crate) neon : uint8x16_t }
52
53 impl Default for u8x16 {
54 #[inline]
55 fn default() -> Self {
56 Self::splat(0)
57 }
58 }
59
60 impl PartialEq for u8x16 {
61 #[inline]
62 fn eq(&self, other: &Self) -> bool {
63 unsafe { vminvq_u8(vceqq_u8(self.neon, other.neon))==u8::MAX }
64 }
65 }
66
67 impl Eq for u8x16 { }
68 } else {
69 #[derive(Default, Clone, Copy, PartialEq, Eq)]
76 #[repr(C, align(16))]
77 pub struct u8x16 { pub(crate) arr: [u8;16] }
78 }
79}
80
81impl_simd_uint! {
82 unsafe {
83 T = u8,
84 N = 16,
85 Simd = u8x16,
86 IntSimd = i8x16,
87 T_BITS = 8,
88 T_BITS_MUL_2 = 16,
89 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
90 optional_type_x86_inner { X86Inner = __m128i },
91 optional_type_arm_inner { ArmInner = uint8x16_t },
92 optional_type_wasm_inner { WasmInner = v128 },
93 }
94
95 #[inline]
96 fn not(self) -> Self::Output {
97 self ^ cast::<u128, u8x16>(u128::MAX)
98 }
99
100 #[inline]
101 fn add(self, rhs: Self) -> Self::Output {
102 pick! {
103 if #[cfg(target_feature="sse2")] {
104 Self { sse: add_i8_m128i(self.sse, rhs.sse) }
105 } else if #[cfg(target_feature="simd128")] {
106 Self { simd: u8x16_add(self.simd, rhs.simd) }
107 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
108 unsafe { Self { neon: vaddq_u8(self.neon, rhs.neon) } }
109 } else {
110 Self { arr: [
111 self.arr[0].wrapping_add(rhs.arr[0]),
112 self.arr[1].wrapping_add(rhs.arr[1]),
113 self.arr[2].wrapping_add(rhs.arr[2]),
114 self.arr[3].wrapping_add(rhs.arr[3]),
115 self.arr[4].wrapping_add(rhs.arr[4]),
116 self.arr[5].wrapping_add(rhs.arr[5]),
117 self.arr[6].wrapping_add(rhs.arr[6]),
118 self.arr[7].wrapping_add(rhs.arr[7]),
119 self.arr[8].wrapping_add(rhs.arr[8]),
120 self.arr[9].wrapping_add(rhs.arr[9]),
121 self.arr[10].wrapping_add(rhs.arr[10]),
122 self.arr[11].wrapping_add(rhs.arr[11]),
123 self.arr[12].wrapping_add(rhs.arr[12]),
124 self.arr[13].wrapping_add(rhs.arr[13]),
125 self.arr[14].wrapping_add(rhs.arr[14]),
126 self.arr[15].wrapping_add(rhs.arr[15]),
127 ]}
128 }
129 }
130 }
131
132 #[inline]
133 fn sub(self, rhs: Self) -> Self::Output {
134 pick! {
135 if #[cfg(target_feature="sse2")] {
136 Self { sse: sub_i8_m128i(self.sse, rhs.sse) }
137 } else if #[cfg(target_feature="simd128")] {
138 Self { simd: u8x16_sub(self.simd, rhs.simd) }
139 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
140 unsafe {Self { neon: vsubq_u8(self.neon, rhs.neon) }}
141 } else {
142 Self { arr: [
143 self.arr[0].wrapping_sub(rhs.arr[0]),
144 self.arr[1].wrapping_sub(rhs.arr[1]),
145 self.arr[2].wrapping_sub(rhs.arr[2]),
146 self.arr[3].wrapping_sub(rhs.arr[3]),
147 self.arr[4].wrapping_sub(rhs.arr[4]),
148 self.arr[5].wrapping_sub(rhs.arr[5]),
149 self.arr[6].wrapping_sub(rhs.arr[6]),
150 self.arr[7].wrapping_sub(rhs.arr[7]),
151 self.arr[8].wrapping_sub(rhs.arr[8]),
152 self.arr[9].wrapping_sub(rhs.arr[9]),
153 self.arr[10].wrapping_sub(rhs.arr[10]),
154 self.arr[11].wrapping_sub(rhs.arr[11]),
155 self.arr[12].wrapping_sub(rhs.arr[12]),
156 self.arr[13].wrapping_sub(rhs.arr[13]),
157 self.arr[14].wrapping_sub(rhs.arr[14]),
158 self.arr[15].wrapping_sub(rhs.arr[15]),
159 ]}
160 }
161 }
162 }
163
164 #[inline]
165 fn mul(self, rhs: Self) -> Self::Output {
166 pick! {
170 if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
171 unsafe { Self { neon: vmulq_u8(self.neon, rhs.neon) } }
172 } else {
173 let self_array: [u8; 16] = cast(self);
174 let rhs_array: [u8; 16] = cast(rhs);
175
176 Self::new([
177 self_array[0].wrapping_mul(rhs_array[0]),
178 self_array[1].wrapping_mul(rhs_array[1]),
179 self_array[2].wrapping_mul(rhs_array[2]),
180 self_array[3].wrapping_mul(rhs_array[3]),
181 self_array[4].wrapping_mul(rhs_array[4]),
182 self_array[5].wrapping_mul(rhs_array[5]),
183 self_array[6].wrapping_mul(rhs_array[6]),
184 self_array[7].wrapping_mul(rhs_array[7]),
185 self_array[8].wrapping_mul(rhs_array[8]),
186 self_array[9].wrapping_mul(rhs_array[9]),
187 self_array[10].wrapping_mul(rhs_array[10]),
188 self_array[11].wrapping_mul(rhs_array[11]),
189 self_array[12].wrapping_mul(rhs_array[12]),
190 self_array[13].wrapping_mul(rhs_array[13]),
191 self_array[14].wrapping_mul(rhs_array[14]),
192 self_array[15].wrapping_mul(rhs_array[15]),
193 ])
194 }
195 }
196 }
197
198 #[inline]
199 fn bitand(self, rhs: Self) -> Self::Output {
200 pick! {
201 if #[cfg(target_feature="sse2")] {
202 Self { sse: bitand_m128i(self.sse, rhs.sse) }
203 } else if #[cfg(target_feature="simd128")] {
204 Self { simd: v128_and(self.simd, rhs.simd) }
205 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
206 unsafe {Self { neon: vandq_u8(self.neon, rhs.neon) }}
207 } else {
208 Self { arr: [
209 self.arr[0].bitand(rhs.arr[0]),
210 self.arr[1].bitand(rhs.arr[1]),
211 self.arr[2].bitand(rhs.arr[2]),
212 self.arr[3].bitand(rhs.arr[3]),
213 self.arr[4].bitand(rhs.arr[4]),
214 self.arr[5].bitand(rhs.arr[5]),
215 self.arr[6].bitand(rhs.arr[6]),
216 self.arr[7].bitand(rhs.arr[7]),
217 self.arr[8].bitand(rhs.arr[8]),
218 self.arr[9].bitand(rhs.arr[9]),
219 self.arr[10].bitand(rhs.arr[10]),
220 self.arr[11].bitand(rhs.arr[11]),
221 self.arr[12].bitand(rhs.arr[12]),
222 self.arr[13].bitand(rhs.arr[13]),
223 self.arr[14].bitand(rhs.arr[14]),
224 self.arr[15].bitand(rhs.arr[15]),
225 ]}
226 }
227 }
228 }
229
230 #[inline]
231 fn bitor(self, rhs: Self) -> Self::Output {
232 pick! {
233 if #[cfg(target_feature="sse2")] {
234 Self { sse: bitor_m128i(self.sse, rhs.sse) }
235 } else if #[cfg(target_feature="simd128")] {
236 Self { simd: v128_or(self.simd, rhs.simd) }
237 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
238 unsafe {Self { neon: vorrq_u8(self.neon, rhs.neon) }}
239 } else {
240 Self { arr: [
241 self.arr[0].bitor(rhs.arr[0]),
242 self.arr[1].bitor(rhs.arr[1]),
243 self.arr[2].bitor(rhs.arr[2]),
244 self.arr[3].bitor(rhs.arr[3]),
245 self.arr[4].bitor(rhs.arr[4]),
246 self.arr[5].bitor(rhs.arr[5]),
247 self.arr[6].bitor(rhs.arr[6]),
248 self.arr[7].bitor(rhs.arr[7]),
249 self.arr[8].bitor(rhs.arr[8]),
250 self.arr[9].bitor(rhs.arr[9]),
251 self.arr[10].bitor(rhs.arr[10]),
252 self.arr[11].bitor(rhs.arr[11]),
253 self.arr[12].bitor(rhs.arr[12]),
254 self.arr[13].bitor(rhs.arr[13]),
255 self.arr[14].bitor(rhs.arr[14]),
256 self.arr[15].bitor(rhs.arr[15]),
257 ]}
258 }
259 }
260 }
261
262 #[inline]
263 fn bitxor(self, rhs: Self) -> Self::Output {
264 pick! {
265 if #[cfg(target_feature="sse2")] {
266 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
267 } else if #[cfg(target_feature="simd128")] {
268 Self { simd: v128_xor(self.simd, rhs.simd) }
269 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
270 unsafe {Self { neon: veorq_u8(self.neon, rhs.neon) }}
271 } else {
272 Self { arr: [
273 self.arr[0].bitxor(rhs.arr[0]),
274 self.arr[1].bitxor(rhs.arr[1]),
275 self.arr[2].bitxor(rhs.arr[2]),
276 self.arr[3].bitxor(rhs.arr[3]),
277 self.arr[4].bitxor(rhs.arr[4]),
278 self.arr[5].bitxor(rhs.arr[5]),
279 self.arr[6].bitxor(rhs.arr[6]),
280 self.arr[7].bitxor(rhs.arr[7]),
281 self.arr[8].bitxor(rhs.arr[8]),
282 self.arr[9].bitxor(rhs.arr[9]),
283 self.arr[10].bitxor(rhs.arr[10]),
284 self.arr[11].bitxor(rhs.arr[11]),
285 self.arr[12].bitxor(rhs.arr[12]),
286 self.arr[13].bitxor(rhs.arr[13]),
287 self.arr[14].bitxor(rhs.arr[14]),
288 self.arr[15].bitxor(rhs.arr[15]),
289 ]}
290 }
291 }
292 }
293
294 #[inline]
295 fn simd_eq(self, rhs: Self) -> Self::Output {
296 pick! {
297 if #[cfg(target_feature="sse2")] {
298 Self { sse: cmp_eq_mask_i8_m128i(self.sse, rhs.sse) }
299 } else if #[cfg(target_feature="simd128")] {
300 Self { simd: u8x16_eq(self.simd, rhs.simd) }
301 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
302 unsafe {Self { neon: vceqq_u8(self.neon, rhs.neon) }}
303 } else {
304 Self { arr: [
305 if self.arr[0] == rhs.arr[0] { u8::MAX } else { 0 },
306 if self.arr[1] == rhs.arr[1] { u8::MAX } else { 0 },
307 if self.arr[2] == rhs.arr[2] { u8::MAX } else { 0 },
308 if self.arr[3] == rhs.arr[3] { u8::MAX } else { 0 },
309 if self.arr[4] == rhs.arr[4] { u8::MAX } else { 0 },
310 if self.arr[5] == rhs.arr[5] { u8::MAX } else { 0 },
311 if self.arr[6] == rhs.arr[6] { u8::MAX } else { 0 },
312 if self.arr[7] == rhs.arr[7] { u8::MAX } else { 0 },
313 if self.arr[8] == rhs.arr[8] { u8::MAX } else { 0 },
314 if self.arr[9] == rhs.arr[9] { u8::MAX } else { 0 },
315 if self.arr[10] == rhs.arr[10] { u8::MAX } else { 0 },
316 if self.arr[11] == rhs.arr[11] { u8::MAX } else { 0 },
317 if self.arr[12] == rhs.arr[12] { u8::MAX } else { 0 },
318 if self.arr[13] == rhs.arr[13] { u8::MAX } else { 0 },
319 if self.arr[14] == rhs.arr[14] { u8::MAX } else { 0 },
320 if self.arr[15] == rhs.arr[15] { u8::MAX } else { 0 },
321 ]}
322 }
323 }
324 }
325
326 #[inline]
327 fn simd_ne(self, rhs: Self) -> Self::Output {
328 pick! {
329 if #[cfg(target_feature="sse2")] {
330 !self.simd_eq(rhs)
331 } else if #[cfg(target_feature="simd128")] {
332 Self { simd: u8x16_ne(self.simd, rhs.simd) }
333 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
334 !self.simd_eq(rhs)
335 } else {
336 Self { arr: [
337 if self.arr[0] != rhs.arr[0] { u8::MAX } else { 0 },
338 if self.arr[1] != rhs.arr[1] { u8::MAX } else { 0 },
339 if self.arr[2] != rhs.arr[2] { u8::MAX } else { 0 },
340 if self.arr[3] != rhs.arr[3] { u8::MAX } else { 0 },
341 if self.arr[4] != rhs.arr[4] { u8::MAX } else { 0 },
342 if self.arr[5] != rhs.arr[5] { u8::MAX } else { 0 },
343 if self.arr[6] != rhs.arr[6] { u8::MAX } else { 0 },
344 if self.arr[7] != rhs.arr[7] { u8::MAX } else { 0 },
345 if self.arr[8] != rhs.arr[8] { u8::MAX } else { 0 },
346 if self.arr[9] != rhs.arr[9] { u8::MAX } else { 0 },
347 if self.arr[10] != rhs.arr[10] { u8::MAX } else { 0 },
348 if self.arr[11] != rhs.arr[11] { u8::MAX } else { 0 },
349 if self.arr[12] != rhs.arr[12] { u8::MAX } else { 0 },
350 if self.arr[13] != rhs.arr[13] { u8::MAX } else { 0 },
351 if self.arr[14] != rhs.arr[14] { u8::MAX } else { 0 },
352 if self.arr[15] != rhs.arr[15] { u8::MAX } else { 0 },
353 ]}
354 }
355 }
356 }
357
358 #[inline]
359 fn simd_lt(self, rhs: Self) -> Self::Output {
360 pick! {
361 if #[cfg(target_feature="sse2")] {
362 let offset = Self::splat(0x80);
364 let self_i8 = self.bitxor(offset).sse;
365 let rhs_i8 = rhs.bitxor(offset).sse;
366 Self { sse: cmp_lt_mask_i8_m128i(self_i8, rhs_i8) }
367 } else if #[cfg(target_feature="simd128")] {
368 Self { simd: u8x16_lt(self.simd, rhs.simd) }
369 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
370 unsafe {Self { neon: vcltq_u8(self.neon, rhs.neon) }}
371 } else {
372 Self { arr: [
373 if self.arr[0] < rhs.arr[0] { u8::MAX } else { 0 },
374 if self.arr[1] < rhs.arr[1] { u8::MAX } else { 0 },
375 if self.arr[2] < rhs.arr[2] { u8::MAX } else { 0 },
376 if self.arr[3] < rhs.arr[3] { u8::MAX } else { 0 },
377 if self.arr[4] < rhs.arr[4] { u8::MAX } else { 0 },
378 if self.arr[5] < rhs.arr[5] { u8::MAX } else { 0 },
379 if self.arr[6] < rhs.arr[6] { u8::MAX } else { 0 },
380 if self.arr[7] < rhs.arr[7] { u8::MAX } else { 0 },
381 if self.arr[8] < rhs.arr[8] { u8::MAX } else { 0 },
382 if self.arr[9] < rhs.arr[9] { u8::MAX } else { 0 },
383 if self.arr[10] < rhs.arr[10] { u8::MAX } else { 0 },
384 if self.arr[11] < rhs.arr[11] { u8::MAX } else { 0 },
385 if self.arr[12] < rhs.arr[12] { u8::MAX } else { 0 },
386 if self.arr[13] < rhs.arr[13] { u8::MAX } else { 0 },
387 if self.arr[14] < rhs.arr[14] { u8::MAX } else { 0 },
388 if self.arr[15] < rhs.arr[15] { u8::MAX } else { 0 },
389 ]}
390 }
391 }
392 }
393
394 #[inline]
395 fn simd_gt(self, rhs: Self) -> Self::Output {
396 pick! {
397 if #[cfg(target_feature="sse2")] {
398 let offset = Self::splat(0x80);
400 let self_i8 = self.bitxor(offset).sse;
401 let rhs_i8 = rhs.bitxor(offset).sse;
402 Self { sse: cmp_gt_mask_i8_m128i(self_i8, rhs_i8) }
403 } else if #[cfg(target_feature="simd128")] {
404 Self { simd: u8x16_gt(self.simd, rhs.simd) }
405 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
406 unsafe {Self { neon: vcgtq_u8(self.neon, rhs.neon) }}
407 } else {
408 Self { arr: [
409 if self.arr[0] > rhs.arr[0] { u8::MAX } else { 0 },
410 if self.arr[1] > rhs.arr[1] { u8::MAX } else { 0 },
411 if self.arr[2] > rhs.arr[2] { u8::MAX } else { 0 },
412 if self.arr[3] > rhs.arr[3] { u8::MAX } else { 0 },
413 if self.arr[4] > rhs.arr[4] { u8::MAX } else { 0 },
414 if self.arr[5] > rhs.arr[5] { u8::MAX } else { 0 },
415 if self.arr[6] > rhs.arr[6] { u8::MAX } else { 0 },
416 if self.arr[7] > rhs.arr[7] { u8::MAX } else { 0 },
417 if self.arr[8] > rhs.arr[8] { u8::MAX } else { 0 },
418 if self.arr[9] > rhs.arr[9] { u8::MAX } else { 0 },
419 if self.arr[10] > rhs.arr[10] { u8::MAX } else { 0 },
420 if self.arr[11] > rhs.arr[11] { u8::MAX } else { 0 },
421 if self.arr[12] > rhs.arr[12] { u8::MAX } else { 0 },
422 if self.arr[13] > rhs.arr[13] { u8::MAX } else { 0 },
423 if self.arr[14] > rhs.arr[14] { u8::MAX } else { 0 },
424 if self.arr[15] > rhs.arr[15] { u8::MAX } else { 0 },
425 ]}
426 }
427 }
428 }
429
430 #[inline]
431 fn simd_le(self, rhs: Self) -> Self::Output {
432 pick! {
433 if #[cfg(target_feature="sse2")] {
434 let offset = Self::splat(0x80);
436 let self_i8 = self.bitxor(offset).sse;
437 let rhs_i8 = rhs.bitxor(offset).sse;
438 let gt_mask = u8x16 { sse: cmp_gt_mask_i8_m128i(self_i8, rhs_i8) };
440 Self { sse: gt_mask.bitxor(u8x16::splat(0xFF)).sse }
441 } else if #[cfg(target_feature="simd128")] {
442 Self { simd: u8x16_le(self.simd, rhs.simd) }
443 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
444 unsafe {Self { neon: vcleq_u8(self.neon, rhs.neon) }}
445 } else {
446 Self { arr: [
447 if self.arr[0] <= rhs.arr[0] { u8::MAX } else { 0 },
448 if self.arr[1] <= rhs.arr[1] { u8::MAX } else { 0 },
449 if self.arr[2] <= rhs.arr[2] { u8::MAX } else { 0 },
450 if self.arr[3] <= rhs.arr[3] { u8::MAX } else { 0 },
451 if self.arr[4] <= rhs.arr[4] { u8::MAX } else { 0 },
452 if self.arr[5] <= rhs.arr[5] { u8::MAX } else { 0 },
453 if self.arr[6] <= rhs.arr[6] { u8::MAX } else { 0 },
454 if self.arr[7] <= rhs.arr[7] { u8::MAX } else { 0 },
455 if self.arr[8] <= rhs.arr[8] { u8::MAX } else { 0 },
456 if self.arr[9] <= rhs.arr[9] { u8::MAX } else { 0 },
457 if self.arr[10] <= rhs.arr[10] { u8::MAX } else { 0 },
458 if self.arr[11] <= rhs.arr[11] { u8::MAX } else { 0 },
459 if self.arr[12] <= rhs.arr[12] { u8::MAX } else { 0 },
460 if self.arr[13] <= rhs.arr[13] { u8::MAX } else { 0 },
461 if self.arr[14] <= rhs.arr[14] { u8::MAX } else { 0 },
462 if self.arr[15] <= rhs.arr[15] { u8::MAX } else { 0 },
463 ]}
464 }
465 }
466 }
467
468 #[inline]
469 fn simd_ge(self, rhs: Self) -> Self::Output {
470 pick! {
471 if #[cfg(target_feature="sse2")] {
472 let offset = Self::splat(0x80);
474 let self_i8 = self.bitxor(offset).sse;
475 let rhs_i8 = rhs.bitxor(offset).sse;
476 let lt_mask = u8x16 { sse: cmp_lt_mask_i8_m128i(self_i8, rhs_i8) };
478 Self { sse: lt_mask.bitxor(u8x16::splat(0xFF)).sse }
479 } else if #[cfg(target_feature="simd128")] {
480 Self { simd: u8x16_ge(self.simd, rhs.simd) }
481 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
482 unsafe {Self { neon: vcgeq_u8(self.neon, rhs.neon) }}
483 } else {
484 Self { arr: [
485 if self.arr[0] >= rhs.arr[0] { u8::MAX } else { 0 },
486 if self.arr[1] >= rhs.arr[1] { u8::MAX } else { 0 },
487 if self.arr[2] >= rhs.arr[2] { u8::MAX } else { 0 },
488 if self.arr[3] >= rhs.arr[3] { u8::MAX } else { 0 },
489 if self.arr[4] >= rhs.arr[4] { u8::MAX } else { 0 },
490 if self.arr[5] >= rhs.arr[5] { u8::MAX } else { 0 },
491 if self.arr[6] >= rhs.arr[6] { u8::MAX } else { 0 },
492 if self.arr[7] >= rhs.arr[7] { u8::MAX } else { 0 },
493 if self.arr[8] >= rhs.arr[8] { u8::MAX } else { 0 },
494 if self.arr[9] >= rhs.arr[9] { u8::MAX } else { 0 },
495 if self.arr[10] >= rhs.arr[10] { u8::MAX } else { 0 },
496 if self.arr[11] >= rhs.arr[11] { u8::MAX } else { 0 },
497 if self.arr[12] >= rhs.arr[12] { u8::MAX } else { 0 },
498 if self.arr[13] >= rhs.arr[13] { u8::MAX } else { 0 },
499 if self.arr[14] >= rhs.arr[14] { u8::MAX } else { 0 },
500 if self.arr[15] >= rhs.arr[15] { u8::MAX } else { 0 },
501 ]}
502 }
503 }
504 }
505
506 #[inline]
507 pub fn reduce_add(self) -> u8 {
508 #[allow(dead_code)]
509 const SHUFFLE_1: [u8; 16] =
510 [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
511 #[allow(dead_code)]
512 const SHUFFLE_2: [u8; 16] =
513 [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
514 #[allow(dead_code)]
515 const SHUFFLE_3: [u8; 16] =
516 [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
517 #[allow(dead_code)]
518 const SHUFFLE_4: [u8; 16] =
519 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
520
521 pick! {
522 if #[cfg(target_feature="ssse3")] {
523 let rhs = shuffle_av_i8z_all_m128i(self.sse, m128i::from(SHUFFLE_1));
524 let sum = add_i8_m128i(self.sse, rhs);
525 let rhs = shuffle_av_i8z_all_m128i(sum, m128i::from(SHUFFLE_2));
526 let sum = add_i8_m128i(sum, rhs);
527 let rhs = shuffle_av_i8z_all_m128i(sum, m128i::from(SHUFFLE_3));
528 let sum = add_i8_m128i(sum, rhs);
529 let rhs = shuffle_av_i8z_all_m128i(sum, m128i::from(SHUFFLE_4));
530 let sum = add_i8_m128i(sum, rhs);
531 get_i32_from_m128i_s(sum) as u8
532 } else if #[cfg(target_feature="simd128")] {
533 let rhs = u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7>(self.simd, self.simd);
534 let sum = u8x16_add(self.simd, rhs);
535 let rhs = u8x16_shuffle::<4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0>(sum, sum);
536 let sum = u8x16_add(sum, rhs);
537 let rhs = u8x16_shuffle::<2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(sum, sum);
538 let sum = u8x16_add(sum, rhs);
539 let rhs = u8x16_shuffle::<1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(sum, sum);
540 let sum = u8x16_add(sum, rhs);
541 u8x16_extract_lane::<0>(sum)
542 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
543 unsafe {
544 let rhs = vqtbl1q_u8(self.neon, core::mem::transmute(SHUFFLE_1));
547 let sum = vaddq_u8(self.neon, rhs);
548 let rhs = vqtbl1q_u8(sum, core::mem::transmute(SHUFFLE_2));
549 let sum = vaddq_u8(sum, rhs);
550 let rhs = vqtbl1q_u8(sum, core::mem::transmute(SHUFFLE_3));
551 let sum = vaddq_u8(sum, rhs);
552 let rhs = vqtbl1q_u8(sum, core::mem::transmute(SHUFFLE_4));
553 let sum = vaddq_u8(sum, rhs);
554 vgetq_lane_u8(sum, 0)
555 }
556 } else {
557 let array: [u8; 16] = cast(self);
558 array.into_iter().reduce(u8::wrapping_add).unwrap()
559 }
560 }
561 }
562
563 #[inline]
564 pub fn reduce_mul(self) -> u8 {
565 pick! {
566 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
567 const HIGH_64: [u8; 16] = [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
568 const HIGH_32: [u8; 16] = [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
569 const HIGH_16: [u8; 16] = [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
570 const HIGH_8: [u8; 16] = [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
571
572 unsafe {
573 let high_64 = vqtbl1q_u8(self.neon, core::mem::transmute(HIGH_64));
576 let reduce_64 = vmulq_u8(self.neon, high_64);
577 let high_32 = vqtbl1q_u8(reduce_64, core::mem::transmute(HIGH_32));
578 let reduce_32 = vmulq_u8(reduce_64, high_32);
579 let high_16 = vqtbl1q_u8(reduce_32, core::mem::transmute(HIGH_16));
580 let reduce_16 = vmulq_u8(reduce_32, high_16);
581 let high_8 = vqtbl1q_u8(reduce_16, core::mem::transmute(HIGH_8));
582 let reduce_8 = vmulq_u8(reduce_16, high_8);
583 vgetq_lane_u8::<0>(reduce_8)
584 }
585 } else {
586 self.to_array().into_iter().reduce(u8::wrapping_mul).unwrap()
587 }
588 }
589 }
590
591 #[inline]
592 pub fn bitselect(self, if_one: Self, if_zero: Self) -> Self {
593 pick! {
594 if #[cfg(target_feature="sse2")] {
595 Self {
596 sse: bitor_m128i(
597 bitand_m128i(if_one.sse, self.sse),
598 bitandnot_m128i(self.sse, if_zero.sse),
599 ),
600 }
601 } else if #[cfg(target_feature="simd128")] {
602 Self { simd: v128_bitselect(if_one.simd, if_zero.simd, self.simd) }
603 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
604 unsafe {Self { neon: vbslq_u8(self.neon, if_one.neon, if_zero.neon) }}
605 } else {
606 generic_bit_blend(self, if_one, if_zero)
607 }
608 }
609 }
610
611 #[inline]
612 fn select(self, if_true: Self, if_false: Self) -> Self {
613 pick! {
614 if #[cfg(target_feature="sse4.1")] {
615 Self { sse: blend_varying_i8_m128i(if_false.sse, if_true.sse, self.sse) }
616 } else if #[cfg(target_feature="simd128")] {
617 Self { simd: v128_bitselect(if_true.simd, if_false.simd, self.simd) }
618 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
619 unsafe {Self { neon: vbslq_u8(self.neon, if_true.neon, if_false.neon) }}
620 } else {
621 generic_bit_blend(self, if_true, if_false)
622 }
623 }
624 }
625
626 #[inline]
627 pub fn to_bitmask(self) -> u32 {
628 pick! {
629 if #[cfg(target_feature="sse2")] {
630 move_mask_i8_m128i(self.sse) as u32
631 } else if #[cfg(target_feature="simd128")] {
632 u8x16_bitmask(self.simd) as u32
633 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
634 unsafe {
635 let masked = vcltzq_s8(self.cast_signed().neon);
637
638 let selectbit : uint8x16_t = core::mem::transmute([1u8, 2, 4, 8, 16, 32, 64, 128, 1, 2, 4, 8, 16, 32, 64, 128]);
640 let out = vandq_u8(masked, selectbit);
641
642 let table : uint8x16_t = core::mem::transmute([0u8, 8, 1, 9, 2, 10, 3, 11, 4, 12, 5, 13, 6, 14, 7, 15]);
644 let r = vqtbl1q_u8(out, table);
645
646 vaddvq_u16(vreinterpretq_u16_u8(r)) as u32
648 }
649 } else {
650 ((self.arr[0].cast_signed() < 0) as u32) |
651 ((self.arr[1].cast_signed() < 0) as u32) << 1 |
652 ((self.arr[2].cast_signed() < 0) as u32) << 2 |
653 ((self.arr[3].cast_signed() < 0) as u32) << 3 |
654 ((self.arr[4].cast_signed() < 0) as u32) << 4 |
655 ((self.arr[5].cast_signed() < 0) as u32) << 5 |
656 ((self.arr[6].cast_signed() < 0) as u32) << 6 |
657 ((self.arr[7].cast_signed() < 0) as u32) << 7 |
658 ((self.arr[8].cast_signed() < 0) as u32) << 8 |
659 ((self.arr[9].cast_signed() < 0) as u32) << 9 |
660 ((self.arr[10].cast_signed() < 0) as u32) << 10 |
661 ((self.arr[11].cast_signed() < 0) as u32) << 11 |
662 ((self.arr[12].cast_signed() < 0) as u32) << 12 |
663 ((self.arr[13].cast_signed() < 0) as u32) << 13 |
664 ((self.arr[14].cast_signed() < 0) as u32) << 14 |
665 ((self.arr[15].cast_signed() < 0) as u32) << 15
666 }
667 }
668 }
669
670 #[inline]
671 pub fn any(self) -> bool {
672 pick! {
673 if #[cfg(target_feature="sse2")] {
674 move_mask_i8_m128i(self.sse) != 0
675 } else if #[cfg(target_feature="simd128")] {
676 u8x16_bitmask(self.simd) != 0
677 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
678 unsafe {
679 vminvq_s8(self.cast_signed().neon) < 0
680 }
681 } else {
682 let v : [u64;2] = cast(self);
683 ((v[0] | v[1]) & 0x8080808080808080) != 0
684 }
685 }
686 }
687
688 #[inline]
689 pub fn all(self) -> bool {
690 pick! {
691 if #[cfg(target_feature="sse2")] {
692 move_mask_i8_m128i(self.sse) == 0b1111_1111_1111_1111
693 } else if #[cfg(target_feature="simd128")] {
694 u8x16_bitmask(self.simd) == 0b1111_1111_1111_1111
695 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
696 unsafe {
697 vmaxvq_s8(self.cast_signed().neon) < 0
698 }
699 } else {
700 let v : [u64;2] = cast(self);
701 (v[0] & v[1] & 0x8080808080808080) == 0x8080808080808080
702 }
703 }
704 }
705
706 #[inline]
707 pub fn shuffle(self, indices: u8x16) -> Self {
708 pick! {
709 if #[cfg(target_feature="ssse3")] {
710 Self { sse: shuffle_av_i8z_all_m128i(self.sse, indices.sse) }
711 } else if #[cfg(target_feature="relaxed-simd")] {
712 Self { simd: u8x16_relaxed_swizzle(self.simd, indices.simd) }
713 } else if #[cfg(target_feature="simd128")] {
714 Self { simd: u8x16_swizzle(self.simd, indices.simd) }
715 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
716 unsafe { Self { neon: vqtbl1q_u8(self.neon, indices.neon) } }
717 } else {
718 let self_array = self.to_array();
719 let indices_array = indices.to_array();
720
721 let mut result = [0; 16];
722 for i in 0..16 {
723 let index = indices_array[i] as usize;
724 if index < 16 {
725 result[i] = self_array[index];
726 }
727 }
728
729 Self::new(result)
730 }
731 }
732 }
733
734 #[inline]
735 pub fn shuffle_zeroing(self, indices: u8x16) -> Self {
736 pick! {
737 if #[cfg(target_feature="ssse3")] {
738 Self {
739 sse: shuffle_av_i8z_all_m128i(
740 self.sse,
741 add_saturating_u8_m128i(indices.sse, set_splat_i8_m128i(0x70)),
742 ),
743 }
744 } else if #[cfg(target_feature="simd128")] {
745 Self { simd: i8x16_swizzle(self.simd, indices.simd) }
746 } else {
747 self.shuffle(indices)
749 }
750 }
751 }
752
753 #[inline]
754 pub fn shuffle_wrapping(self, indices: u8x16) -> Self {
755 pick! {
756 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
757 #[cfg(target_arch = "x86")]
758 use core::arch::x86::_mm_permutexvar_epi8;
759 #[cfg(target_arch = "x86_64")]
760 use core::arch::x86_64::_mm_permutexvar_epi8;
761
762 Self { sse: unsafe { m128i(_mm_permutexvar_epi8(indices.sse.0, self.sse.0)) } }
764 } else {
765 self.shuffle(indices & 15)
766 }
767 }
768 }
769
770 #[inline]
771 fn shuffle(self: [u8x16; 2], indices: u8x16) -> u8x16 {
772 pick! {
773 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
774 #[cfg(target_arch = "x86")]
775 use core::arch::x86::_mm_permutex2var_epi8;
776 #[cfg(target_arch = "x86_64")]
777 use core::arch::x86_64::_mm_permutex2var_epi8;
778
779 u8x16 {
781 sse: unsafe {
782 m128i(_mm_permutex2var_epi8(self[0].sse.0, indices.sse.0, self[1].sse.0))
783 },
784 }
785 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
786 let table = uint8x16x2_t(self[0].neon, self[1].neon);
787 unsafe { u8x16 { neon: vqtbl2q_u8(table, indices.neon) } }
788 } else {
789 self[0].shuffle_zeroing(indices) | self[1].shuffle_zeroing(indices - 16)
790 }
791 }
792 }
793
794 #[inline]
795 fn shuffle_zeroing(self: [u8x16; 2], indices: u8x16) -> u8x16 {
796 pick! {
797 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
798 self.shuffle(indices) & indices.simd_lt(32)
799 } else {
800 self.shuffle(indices)
801 }
802 }
803 }
804
805 #[inline]
806 fn shuffle_wrapping(self: [u8x16; 2], indices: u8x16) -> u8x16 {
807 pick! {
808 if #[cfg(all(target_feature = "avx512vbmi", target_feature = "avx512vl"))] {
809 self.shuffle(indices)
811 } else {
812 self.shuffle(indices & 31)
813 }
814 }
815 }
816
817 #[inline]
818 fn shuffle(self: [u8x16; 3], indices: u8x16) -> u8x16 {
819 pick! {
820 if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
821 let table = uint8x16x3_t(self[0].neon, self[1].neon, self[2].neon);
822 unsafe { u8x16 { neon: vqtbl3q_u8(table, indices.neon) } }
823 } else {
824 [self[0], self[1]].shuffle_zeroing(indices) | self[2].shuffle_zeroing(indices - 32)
825 }
826 }
827 }
828
829 #[inline]
830 fn shuffle_zeroing(self: [u8x16; 3], indices: u8x16) -> u8x16 {
831 self.shuffle(indices)
832 }
833
834 #[inline]
835 fn shuffle_wrapping(self: [u8x16; 3], indices: u8x16) -> u8x16 {
836 self.shuffle(indices % 48)
837 }
838
839 #[inline]
840 fn shuffle(self: [u8x16; 4], indices: u8x16) -> u8x16 {
841 pick! {
842 if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
843 let table = uint8x16x4_t(self[0].neon, self[1].neon, self[2].neon, self[3].neon);
844 unsafe { u8x16 { neon: vqtbl4q_u8(table, indices.neon) } }
845 } else {
846 [self[0], self[1]].shuffle_zeroing(indices)
847 | [self[2], self[3]].shuffle_zeroing(indices - 32)
848 }
849 }
850 }
851
852 #[inline]
853 fn shuffle_zeroing(self: [u8x16; 4], indices: u8x16) -> u8x16 {
854 self.shuffle(indices)
855 }
856
857 #[inline]
858 fn shuffle_wrapping(self: [u8x16; 4], indices: u8x16) -> u8x16 {
859 self.shuffle(indices & 63)
860 }
861
862 #[inline]
865 pub fn transpose(data: [Self; 16]) -> [Self; 16] {
866 #[inline(always)]
869 fn transpose_column(data: &[u8x16; 16], index: usize) -> u8x16 {
870 u8x16::new([
871 data[0].as_array()[index],
872 data[1].as_array()[index],
873 data[2].as_array()[index],
874 data[3].as_array()[index],
875 data[4].as_array()[index],
876 data[5].as_array()[index],
877 data[6].as_array()[index],
878 data[7].as_array()[index],
879 data[8].as_array()[index],
880 data[9].as_array()[index],
881 data[10].as_array()[index],
882 data[11].as_array()[index],
883 data[12].as_array()[index],
884 data[13].as_array()[index],
885 data[14].as_array()[index],
886 data[15].as_array()[index],
887 ])
888 }
889
890 [
891 transpose_column(&data, 0),
892 transpose_column(&data, 1),
893 transpose_column(&data, 2),
894 transpose_column(&data, 3),
895 transpose_column(&data, 4),
896 transpose_column(&data, 5),
897 transpose_column(&data, 6),
898 transpose_column(&data, 7),
899 transpose_column(&data, 8),
900 transpose_column(&data, 9),
901 transpose_column(&data, 10),
902 transpose_column(&data, 11),
903 transpose_column(&data, 12),
904 transpose_column(&data, 13),
905 transpose_column(&data, 14),
906 transpose_column(&data, 15),
907 ]
908 }
909
910 #[inline]
911 fn shl(self, rhs: Self) -> Self::Output {
912 pick! {
916 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
917 unsafe {
918 let shift_by = vreinterpretq_s8_u8(vandq_u8(rhs.neon, vmovq_n_u8(7)));
920 Self { neon: vshlq_u8(self.neon, shift_by) }
921 }
922 } else {
923 let self_array: [u8; 16] = cast(self);
924 let rhs_array: [u8; 16] = cast(rhs);
925
926 Self::new([
927 self_array[0].wrapping_shl(rhs_array[0] as u32),
928 self_array[1].wrapping_shl(rhs_array[1] as u32),
929 self_array[2].wrapping_shl(rhs_array[2] as u32),
930 self_array[3].wrapping_shl(rhs_array[3] as u32),
931 self_array[4].wrapping_shl(rhs_array[4] as u32),
932 self_array[5].wrapping_shl(rhs_array[5] as u32),
933 self_array[6].wrapping_shl(rhs_array[6] as u32),
934 self_array[7].wrapping_shl(rhs_array[7] as u32),
935 self_array[8].wrapping_shl(rhs_array[8] as u32),
936 self_array[9].wrapping_shl(rhs_array[9] as u32),
937 self_array[10].wrapping_shl(rhs_array[10] as u32),
938 self_array[11].wrapping_shl(rhs_array[11] as u32),
939 self_array[12].wrapping_shl(rhs_array[12] as u32),
940 self_array[13].wrapping_shl(rhs_array[13] as u32),
941 self_array[14].wrapping_shl(rhs_array[14] as u32),
942 self_array[15].wrapping_shl(rhs_array[15] as u32),
943 ])
944 }
945 }
946 }
947
948 #[inline]
949 fn shl(self, rhs: u32) -> Self::Output {
950 pick! {
954 if #[cfg(target_feature="simd128")] {
955 Self { simd: u8x16_shl(self.simd, rhs & 7) }
957 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
958 unsafe { Self { neon: vshlq_u8(self.neon, vmovq_n_s8(rhs as i8 & 7)) } }
960 } else {
961 let values: u16x8 = cast(self);
962 let shift = rhs & 7;
963 let shifted = values << shift;
964 let crossed = u16x8::splat(!((0x00FFu16 << shift) & 0xFF00));
965 cast(shifted & crossed)
966 }
967 }
968 }
969
970 #[inline]
971 fn shr(self, rhs: Self) -> Self::Output {
972 pick! {
976 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
977 unsafe {
978 let neg_rhs = vnegq_s8(vreinterpretq_s8_u8(vandq_u8(rhs.neon, vmovq_n_u8(7))));
981 Self { neon: vshlq_u8(self.neon, neg_rhs) }
982 }
983 } else {
984 let self_array: [u8; 16] = cast(self);
985 let rhs_array: [u8; 16] = cast(rhs);
986
987 Self::new([
988 self_array[0].wrapping_shr(rhs_array[0] as u32),
989 self_array[1].wrapping_shr(rhs_array[1] as u32),
990 self_array[2].wrapping_shr(rhs_array[2] as u32),
991 self_array[3].wrapping_shr(rhs_array[3] as u32),
992 self_array[4].wrapping_shr(rhs_array[4] as u32),
993 self_array[5].wrapping_shr(rhs_array[5] as u32),
994 self_array[6].wrapping_shr(rhs_array[6] as u32),
995 self_array[7].wrapping_shr(rhs_array[7] as u32),
996 self_array[8].wrapping_shr(rhs_array[8] as u32),
997 self_array[9].wrapping_shr(rhs_array[9] as u32),
998 self_array[10].wrapping_shr(rhs_array[10] as u32),
999 self_array[11].wrapping_shr(rhs_array[11] as u32),
1000 self_array[12].wrapping_shr(rhs_array[12] as u32),
1001 self_array[13].wrapping_shr(rhs_array[13] as u32),
1002 self_array[14].wrapping_shr(rhs_array[14] as u32),
1003 self_array[15].wrapping_shr(rhs_array[15] as u32),
1004 ])
1005 }
1006 }
1007 }
1008
1009 #[inline]
1010 fn shr(self, rhs: u32) -> Self::Output {
1011 pick! {
1015 if #[cfg(target_feature="simd128")] {
1016 Self { simd: u8x16_shr(self.simd, rhs & 7) }
1018 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1019 unsafe { Self { neon: vshlq_u8(self.neon, vmovq_n_s8(-(rhs as i8 & 7))) } }
1022 } else {
1023 let values: u16x8 = cast(self);
1024 let shift = rhs & 7;
1025 let shifted = values >> shift;
1026 let crossed = u16x8::splat(!((0xFF00u16 >> shift) & 0x00FF));
1027 cast(shifted & crossed)
1028 }
1029 }
1030 }
1031
1032 #[inline]
1033 pub fn max(self, rhs: Self) -> Self {
1034 pick! {
1035 if #[cfg(target_feature="sse2")] {
1036 Self { sse: max_u8_m128i(self.sse, rhs.sse) }
1037 } else if #[cfg(target_feature="simd128")] {
1038 Self { simd: u8x16_max(self.simd, rhs.simd) }
1039 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1040 unsafe {Self { neon: vmaxq_u8(self.neon, rhs.neon) }}
1041 } else {
1042 Self { arr: [
1043 self.arr[0].max(rhs.arr[0]),
1044 self.arr[1].max(rhs.arr[1]),
1045 self.arr[2].max(rhs.arr[2]),
1046 self.arr[3].max(rhs.arr[3]),
1047 self.arr[4].max(rhs.arr[4]),
1048 self.arr[5].max(rhs.arr[5]),
1049 self.arr[6].max(rhs.arr[6]),
1050 self.arr[7].max(rhs.arr[7]),
1051 self.arr[8].max(rhs.arr[8]),
1052 self.arr[9].max(rhs.arr[9]),
1053 self.arr[10].max(rhs.arr[10]),
1054 self.arr[11].max(rhs.arr[11]),
1055 self.arr[12].max(rhs.arr[12]),
1056 self.arr[13].max(rhs.arr[13]),
1057 self.arr[14].max(rhs.arr[14]),
1058 self.arr[15].max(rhs.arr[15]),
1059 ]}
1060 }
1061 }
1062 }
1063
1064 #[inline]
1065 pub fn min(self, rhs: Self) -> Self {
1066 pick! {
1067 if #[cfg(target_feature="sse2")] {
1068 Self { sse: min_u8_m128i(self.sse, rhs.sse) }
1069 } else if #[cfg(target_feature="simd128")] {
1070 Self { simd: u8x16_min(self.simd, rhs.simd) }
1071 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1072 unsafe {Self { neon: vminq_u8(self.neon, rhs.neon) }}
1073 } else {
1074 Self { arr: [
1075 self.arr[0].min(rhs.arr[0]),
1076 self.arr[1].min(rhs.arr[1]),
1077 self.arr[2].min(rhs.arr[2]),
1078 self.arr[3].min(rhs.arr[3]),
1079 self.arr[4].min(rhs.arr[4]),
1080 self.arr[5].min(rhs.arr[5]),
1081 self.arr[6].min(rhs.arr[6]),
1082 self.arr[7].min(rhs.arr[7]),
1083 self.arr[8].min(rhs.arr[8]),
1084 self.arr[9].min(rhs.arr[9]),
1085 self.arr[10].min(rhs.arr[10]),
1086 self.arr[11].min(rhs.arr[11]),
1087 self.arr[12].min(rhs.arr[12]),
1088 self.arr[13].min(rhs.arr[13]),
1089 self.arr[14].min(rhs.arr[14]),
1090 self.arr[15].min(rhs.arr[15]),
1091 ]}
1092 }
1093 }
1094 }
1095
1096 #[inline]
1097 pub fn reduce_max(self) -> u8 {
1098 #[allow(dead_code)]
1099 const SHUFFLE_1: [i8; 16] =
1100 [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
1101 #[allow(dead_code)]
1102 const SHUFFLE_2: [i8; 16] =
1103 [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
1104 #[allow(dead_code)]
1105 const SHUFFLE_3: [i8; 16] =
1106 [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1107 #[allow(dead_code)]
1108 const SHUFFLE_4: [i8; 16] =
1109 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1110
1111 pick! {
1112 if #[cfg(target_feature="ssse3")] {
1113 let rhs = shuffle_av_i8z_all_m128i(self.sse, m128i::from(SHUFFLE_1));
1114 let max = max_u8_m128i(self.sse, rhs);
1115 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_2));
1116 let max = max_u8_m128i(max, rhs);
1117 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_3));
1118 let max = max_u8_m128i(max, rhs);
1119 let rhs = shuffle_av_i8z_all_m128i(max, m128i::from(SHUFFLE_4));
1120 let max = max_u8_m128i(max, rhs);
1121 get_i32_from_m128i_s(max) as u8
1122 } else if #[cfg(target_feature="simd128")] {
1123 let rhs = u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7>(self.simd, self.simd);
1124 let max = u8x16_max(self.simd, rhs);
1125 let rhs = u8x16_shuffle::<4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
1126 let max = u8x16_max(max, rhs);
1127 let rhs = u8x16_shuffle::<2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
1128 let max = u8x16_max(max, rhs);
1129 let rhs = u8x16_shuffle::<1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(max, max);
1130 let max = u8x16_max(max, rhs);
1131 u8x16_extract_lane::<0>(max)
1132 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1133 unsafe {
1134 let rhs = vqtbl1q_u8(self.neon, core::mem::transmute(SHUFFLE_1));
1137 let max = vmaxq_u8(self.neon, rhs);
1138 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_2));
1139 let max = vmaxq_u8(max, rhs);
1140 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_3));
1141 let max = vmaxq_u8(max, rhs);
1142 let rhs = vqtbl1q_u8(max, core::mem::transmute(SHUFFLE_4));
1143 let max = vmaxq_u8(max, rhs);
1144 vgetq_lane_u8(max, 0)
1145 }
1146 } else {
1147 let array: [u8; 16] = cast(self);
1148 array.into_iter().reduce(u8::max).unwrap()
1149 }
1150 }
1151 }
1152
1153 #[inline]
1154 pub fn reduce_min(self) -> u8 {
1155 #[allow(dead_code)]
1156 const SHUFFLE_1: [i8; 16] =
1157 [8, 9, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0];
1158 #[allow(dead_code)]
1159 const SHUFFLE_2: [i8; 16] =
1160 [4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0];
1161 #[allow(dead_code)]
1162 const SHUFFLE_3: [i8; 16] =
1163 [2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1164 #[allow(dead_code)]
1165 const SHUFFLE_4: [i8; 16] =
1166 [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
1167
1168 pick! {
1169 if #[cfg(target_feature="ssse3")] {
1170 let rhs = shuffle_av_i8z_all_m128i(self.sse, m128i::from(SHUFFLE_1));
1171 let min = min_u8_m128i(self.sse, rhs);
1172 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_2));
1173 let min = min_u8_m128i(min, rhs);
1174 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_3));
1175 let min = min_u8_m128i(min, rhs);
1176 let rhs = shuffle_av_i8z_all_m128i(min, m128i::from(SHUFFLE_4));
1177 let min = min_u8_m128i(min, rhs);
1178 get_i32_from_m128i_s(min) as u8
1179 } else if #[cfg(target_feature="simd128")] {
1180 let rhs = u8x16_shuffle::<8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7>(self.simd, self.simd);
1181 let min = u8x16_min(self.simd, rhs);
1182 let rhs = u8x16_shuffle::<4, 5, 6, 7, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
1183 let min = u8x16_min(min, rhs);
1184 let rhs = u8x16_shuffle::<2, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
1185 let min = u8x16_min(min, rhs);
1186 let rhs = u8x16_shuffle::<1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0>(min, min);
1187 let min = u8x16_min(min, rhs);
1188 u8x16_extract_lane::<0>(min)
1189 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1190 unsafe {
1191 let rhs = vqtbl1q_u8(self.neon, core::mem::transmute(SHUFFLE_1));
1194 let min = vminq_u8(self.neon, rhs);
1195 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_2));
1196 let min = vminq_u8(min, rhs);
1197 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_3));
1198 let min = vminq_u8(min, rhs);
1199 let rhs = vqtbl1q_u8(min, core::mem::transmute(SHUFFLE_4));
1200 let min = vminq_u8(min, rhs);
1201 vgetq_lane_u8(min, 0)
1202 }
1203 } else {
1204 let array: [u8; 16] = cast(self);
1205 array.into_iter().reduce(u8::min).unwrap()
1206 }
1207 }
1208 }
1209
1210 #[inline]
1211 pub fn unbounded_shl(self, rhs: Self) -> Self {
1212 pick! {
1216 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1217 unsafe {
1218 Self { neon: vshlq_u8(self.neon, vreinterpretq_s8_u8(rhs.neon)) } & rhs.simd_lt(8)
1219 }
1220 } else {
1221 let self_array = self.to_array();
1222 let rhs_array = rhs.to_array();
1223
1224 Self::new([
1225 self_array[0].unbounded_shl(rhs_array[0] as u32),
1226 self_array[1].unbounded_shl(rhs_array[1] as u32),
1227 self_array[2].unbounded_shl(rhs_array[2] as u32),
1228 self_array[3].unbounded_shl(rhs_array[3] as u32),
1229 self_array[4].unbounded_shl(rhs_array[4] as u32),
1230 self_array[5].unbounded_shl(rhs_array[5] as u32),
1231 self_array[6].unbounded_shl(rhs_array[6] as u32),
1232 self_array[7].unbounded_shl(rhs_array[7] as u32),
1233 self_array[8].unbounded_shl(rhs_array[8] as u32),
1234 self_array[9].unbounded_shl(rhs_array[9] as u32),
1235 self_array[10].unbounded_shl(rhs_array[10] as u32),
1236 self_array[11].unbounded_shl(rhs_array[11] as u32),
1237 self_array[12].unbounded_shl(rhs_array[12] as u32),
1238 self_array[13].unbounded_shl(rhs_array[13] as u32),
1239 self_array[14].unbounded_shl(rhs_array[14] as u32),
1240 self_array[15].unbounded_shl(rhs_array[15] as u32),
1241 ])
1242 }
1243 }
1244 }
1245
1246 #[inline]
1247 pub fn unbounded_shl_scalar(self, rhs: u32) -> Self {
1248 pick! {
1252 if #[cfg(target_feature="simd128")] {
1253 if rhs >= 8 { Self::ZERO } else { Self { simd: u8x16_shl(self.simd, rhs) } }
1255 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1256 unsafe { Self { neon: vshlq_u8(self.neon, vmovq_n_s8(rhs.min(i8::MAX as u32) as i8)) } }
1258 } else {
1259 let values: u16x8 = cast(self);
1260 let shifted = values.unbounded_shl_scalar(rhs);
1261 let crossed = u16x8::splat(!(0x00FFu16.wrapping_shl(rhs) & 0xFF00));
1262 cast(shifted & crossed)
1263 }
1264 }
1265 }
1266
1267 #[inline]
1268 pub fn unbounded_shr(self, rhs: Self) -> Self {
1269 pick! {
1273 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1274 unsafe {
1275 Self { neon: vshlq_u8(self.neon, vnegq_s8(vreinterpretq_s8_u8(rhs.neon))) } & rhs.simd_lt(8)
1278 }
1279 } else {
1280 let self_array = self.to_array();
1281 let rhs_array = rhs.to_array();
1282
1283 Self::new([
1284 self_array[0].unbounded_shr(rhs_array[0] as u32),
1285 self_array[1].unbounded_shr(rhs_array[1] as u32),
1286 self_array[2].unbounded_shr(rhs_array[2] as u32),
1287 self_array[3].unbounded_shr(rhs_array[3] as u32),
1288 self_array[4].unbounded_shr(rhs_array[4] as u32),
1289 self_array[5].unbounded_shr(rhs_array[5] as u32),
1290 self_array[6].unbounded_shr(rhs_array[6] as u32),
1291 self_array[7].unbounded_shr(rhs_array[7] as u32),
1292 self_array[8].unbounded_shr(rhs_array[8] as u32),
1293 self_array[9].unbounded_shr(rhs_array[9] as u32),
1294 self_array[10].unbounded_shr(rhs_array[10] as u32),
1295 self_array[11].unbounded_shr(rhs_array[11] as u32),
1296 self_array[12].unbounded_shr(rhs_array[12] as u32),
1297 self_array[13].unbounded_shr(rhs_array[13] as u32),
1298 self_array[14].unbounded_shr(rhs_array[14] as u32),
1299 self_array[15].unbounded_shr(rhs_array[15] as u32),
1300 ])
1301 }
1302 }
1303 }
1304
1305 #[inline]
1306 pub fn unbounded_shr_scalar(self, rhs: u32) -> Self {
1307 pick! {
1311 if #[cfg(target_feature="simd128")] {
1312 if rhs < 8 { Self { simd: u8x16_shr(self.simd, rhs) } } else { Self::ZERO }
1313 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1314 unsafe {
1315 Self { neon: vshlq_u8(self.neon, vmovq_n_s8(-rhs.min(8).cast_signed() as i8)) }
1318 }
1319 } else {
1320 let values: u16x8 = cast(self);
1321 let shifted = values.unbounded_shr_scalar(rhs);
1322 let crossed = u16x8::splat(!(0xFF00u16.wrapping_shr(rhs) & 0x00FF));
1323 cast(shifted & crossed)
1324 }
1325 }
1326 }
1327
1328 #[inline]
1329 pub fn saturating_add(self, rhs: Self) -> Self {
1330 pick! {
1331 if #[cfg(target_feature="sse2")] {
1332 Self { sse: add_saturating_u8_m128i(self.sse, rhs.sse) }
1333 } else if #[cfg(target_feature="simd128")] {
1334 Self { simd: u8x16_add_sat(self.simd, rhs.simd) }
1335 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1336 unsafe {Self { neon: vqaddq_u8(self.neon, rhs.neon) }}
1337 } else {
1338 Self { arr: [
1339 self.arr[0].saturating_add(rhs.arr[0]),
1340 self.arr[1].saturating_add(rhs.arr[1]),
1341 self.arr[2].saturating_add(rhs.arr[2]),
1342 self.arr[3].saturating_add(rhs.arr[3]),
1343 self.arr[4].saturating_add(rhs.arr[4]),
1344 self.arr[5].saturating_add(rhs.arr[5]),
1345 self.arr[6].saturating_add(rhs.arr[6]),
1346 self.arr[7].saturating_add(rhs.arr[7]),
1347 self.arr[8].saturating_add(rhs.arr[8]),
1348 self.arr[9].saturating_add(rhs.arr[9]),
1349 self.arr[10].saturating_add(rhs.arr[10]),
1350 self.arr[11].saturating_add(rhs.arr[11]),
1351 self.arr[12].saturating_add(rhs.arr[12]),
1352 self.arr[13].saturating_add(rhs.arr[13]),
1353 self.arr[14].saturating_add(rhs.arr[14]),
1354 self.arr[15].saturating_add(rhs.arr[15]),
1355 ]}
1356 }
1357 }
1358 }
1359
1360 #[inline]
1361 pub fn saturating_sub(self, rhs: Self) -> Self {
1362 pick! {
1363 if #[cfg(target_feature="sse2")] {
1364 Self { sse: sub_saturating_u8_m128i(self.sse, rhs.sse) }
1365 } else if #[cfg(target_feature="simd128")] {
1366 Self { simd: u8x16_sub_sat(self.simd, rhs.simd) }
1367 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1368 unsafe { Self { neon: vqsubq_u8(self.neon, rhs.neon) } }
1369 } else {
1370 Self { arr: [
1371 self.arr[0].saturating_sub(rhs.arr[0]),
1372 self.arr[1].saturating_sub(rhs.arr[1]),
1373 self.arr[2].saturating_sub(rhs.arr[2]),
1374 self.arr[3].saturating_sub(rhs.arr[3]),
1375 self.arr[4].saturating_sub(rhs.arr[4]),
1376 self.arr[5].saturating_sub(rhs.arr[5]),
1377 self.arr[6].saturating_sub(rhs.arr[6]),
1378 self.arr[7].saturating_sub(rhs.arr[7]),
1379 self.arr[8].saturating_sub(rhs.arr[8]),
1380 self.arr[9].saturating_sub(rhs.arr[9]),
1381 self.arr[10].saturating_sub(rhs.arr[10]),
1382 self.arr[11].saturating_sub(rhs.arr[11]),
1383 self.arr[12].saturating_sub(rhs.arr[12]),
1384 self.arr[13].saturating_sub(rhs.arr[13]),
1385 self.arr[14].saturating_sub(rhs.arr[14]),
1386 self.arr[15].saturating_sub(rhs.arr[15]),
1387 ]}
1388 }
1389 }
1390 }
1391
1392 #[inline]
1393 pub fn overflowing_mul(self, rhs: Self) -> (Self, Self) {
1394 let (low, high) = self.mul_keep_low_high(rhs);
1395 let overflow = high.simd_ne(Self::ZERO);
1396 (low, overflow)
1397 }
1398
1399 optional_fn_widening_mul {
1400 #[inline]
1401 pub fn widening_mul(self, rhs: Self) -> u16x16 {
1402 pick! {
1403 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1404 unsafe {
1405 let low_wide_mul = vmull_u8(vget_low_u8(self.neon), vget_low_u8(rhs.neon));
1406 let high_wide_mul = vmull_u8(vget_high_u8(self.neon), vget_high_u8(rhs.neon));
1407
1408 u16x16 {
1409 a: u16x8 { neon: low_wide_mul },
1410 b: u16x8 { neon: high_wide_mul },
1411 }
1412 }
1413 } else {
1414 let self_array = self.to_array();
1415 let rhs_array = rhs.to_array();
1416
1417 u16x16::new([
1418 (self_array[0] as u16).wrapping_mul(rhs_array[0] as u16),
1419 (self_array[1] as u16).wrapping_mul(rhs_array[1] as u16),
1420 (self_array[2] as u16).wrapping_mul(rhs_array[2] as u16),
1421 (self_array[3] as u16).wrapping_mul(rhs_array[3] as u16),
1422 (self_array[4] as u16).wrapping_mul(rhs_array[4] as u16),
1423 (self_array[5] as u16).wrapping_mul(rhs_array[5] as u16),
1424 (self_array[6] as u16).wrapping_mul(rhs_array[6] as u16),
1425 (self_array[7] as u16).wrapping_mul(rhs_array[7] as u16),
1426 (self_array[8] as u16).wrapping_mul(rhs_array[8] as u16),
1427 (self_array[9] as u16).wrapping_mul(rhs_array[9] as u16),
1428 (self_array[10] as u16).wrapping_mul(rhs_array[10] as u16),
1429 (self_array[11] as u16).wrapping_mul(rhs_array[11] as u16),
1430 (self_array[12] as u16).wrapping_mul(rhs_array[12] as u16),
1431 (self_array[13] as u16).wrapping_mul(rhs_array[13] as u16),
1432 (self_array[14] as u16).wrapping_mul(rhs_array[14] as u16),
1433 (self_array[15] as u16).wrapping_mul(rhs_array[15] as u16),
1434 ])
1435 }
1436 }
1437 }
1438 }
1439
1440 #[inline]
1441 pub fn mul_keep_low_high(self, rhs: Self) -> (Self, Self) {
1442 pick! {
1443 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1444 unsafe {
1445 let low_wide_mul = vreinterpretq_u8_u16(
1446 vmull_u8(vget_low_u8(self.neon), vget_low_u8(rhs.neon)),
1447 );
1448 let high_wide_mul = vreinterpretq_u8_u16(
1449 vmull_u8(vget_high_u8(self.neon), vget_high_u8(rhs.neon)),
1450 );
1451 let low_high = vuzpq_u8(low_wide_mul, high_wide_mul);
1452 (
1453 Self { neon: low_high.0 },
1454 Self { neon: low_high.1 },
1455 )
1456 }
1457 } else {
1458 let self_array = self.to_array();
1462 let rhs_array = rhs.to_array();
1463
1464 let widening_mul = [
1465 (self_array[0] as u16).wrapping_mul(rhs_array[0] as u16),
1466 (self_array[1] as u16).wrapping_mul(rhs_array[1] as u16),
1467 (self_array[2] as u16).wrapping_mul(rhs_array[2] as u16),
1468 (self_array[3] as u16).wrapping_mul(rhs_array[3] as u16),
1469 (self_array[4] as u16).wrapping_mul(rhs_array[4] as u16),
1470 (self_array[5] as u16).wrapping_mul(rhs_array[5] as u16),
1471 (self_array[6] as u16).wrapping_mul(rhs_array[6] as u16),
1472 (self_array[7] as u16).wrapping_mul(rhs_array[7] as u16),
1473 (self_array[8] as u16).wrapping_mul(rhs_array[8] as u16),
1474 (self_array[9] as u16).wrapping_mul(rhs_array[9] as u16),
1475 (self_array[10] as u16).wrapping_mul(rhs_array[10] as u16),
1476 (self_array[11] as u16).wrapping_mul(rhs_array[11] as u16),
1477 (self_array[12] as u16).wrapping_mul(rhs_array[12] as u16),
1478 (self_array[13] as u16).wrapping_mul(rhs_array[13] as u16),
1479 (self_array[14] as u16).wrapping_mul(rhs_array[14] as u16),
1480 (self_array[15] as u16).wrapping_mul(rhs_array[15] as u16),
1481 ];
1482
1483 (
1484 Self::new([
1485 widening_mul[0] as u8,
1486 widening_mul[1] as u8,
1487 widening_mul[2] as u8,
1488 widening_mul[3] as u8,
1489 widening_mul[4] as u8,
1490 widening_mul[5] as u8,
1491 widening_mul[6] as u8,
1492 widening_mul[7] as u8,
1493 widening_mul[8] as u8,
1494 widening_mul[9] as u8,
1495 widening_mul[10] as u8,
1496 widening_mul[11] as u8,
1497 widening_mul[12] as u8,
1498 widening_mul[13] as u8,
1499 widening_mul[14] as u8,
1500 widening_mul[15] as u8,
1501 ]),
1502 Self::new([
1503 (widening_mul[0] >> 8) as u8,
1504 (widening_mul[1] >> 8) as u8,
1505 (widening_mul[2] >> 8) as u8,
1506 (widening_mul[3] >> 8) as u8,
1507 (widening_mul[4] >> 8) as u8,
1508 (widening_mul[5] >> 8) as u8,
1509 (widening_mul[6] >> 8) as u8,
1510 (widening_mul[7] >> 8) as u8,
1511 (widening_mul[8] >> 8) as u8,
1512 (widening_mul[9] >> 8) as u8,
1513 (widening_mul[10] >> 8) as u8,
1514 (widening_mul[11] >> 8) as u8,
1515 (widening_mul[12] >> 8) as u8,
1516 (widening_mul[13] >> 8) as u8,
1517 (widening_mul[14] >> 8) as u8,
1518 (widening_mul[15] >> 8) as u8,
1519 ]),
1520 )
1521 }
1522 }
1523 }
1524
1525 #[inline]
1526 pub fn mul_keep_high(self, rhs: Self) -> Self {
1527 pick! {
1528 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1529 unsafe {
1530 let low_wide_mul = vreinterpretq_u8_u16(
1531 vmull_u8(vget_low_u8(self.neon), vget_low_u8(rhs.neon)),
1532 );
1533 let high_wide_mul = vreinterpretq_u8_u16(
1534 vmull_u8(vget_high_u8(self.neon), vget_high_u8(rhs.neon)),
1535 );
1536 Self { neon: vuzpq_u8(low_wide_mul, high_wide_mul).1 }
1537 }
1538 } else {
1539 let self_array = self.to_array();
1540 let rhs_array = rhs.to_array();
1541
1542 Self::new([
1543 ((self_array[0] as u16).wrapping_mul(rhs_array[0] as u16) >> 8) as u8,
1544 ((self_array[1] as u16).wrapping_mul(rhs_array[1] as u16) >> 8) as u8,
1545 ((self_array[2] as u16).wrapping_mul(rhs_array[2] as u16) >> 8) as u8,
1546 ((self_array[3] as u16).wrapping_mul(rhs_array[3] as u16) >> 8) as u8,
1547 ((self_array[4] as u16).wrapping_mul(rhs_array[4] as u16) >> 8) as u8,
1548 ((self_array[5] as u16).wrapping_mul(rhs_array[5] as u16) >> 8) as u8,
1549 ((self_array[6] as u16).wrapping_mul(rhs_array[6] as u16) >> 8) as u8,
1550 ((self_array[7] as u16).wrapping_mul(rhs_array[7] as u16) >> 8) as u8,
1551 ((self_array[8] as u16).wrapping_mul(rhs_array[8] as u16) >> 8) as u8,
1552 ((self_array[9] as u16).wrapping_mul(rhs_array[9] as u16) >> 8) as u8,
1553 ((self_array[10] as u16).wrapping_mul(rhs_array[10] as u16) >> 8) as u8,
1554 ((self_array[11] as u16).wrapping_mul(rhs_array[11] as u16) >> 8) as u8,
1555 ((self_array[12] as u16).wrapping_mul(rhs_array[12] as u16) >> 8) as u8,
1556 ((self_array[13] as u16).wrapping_mul(rhs_array[13] as u16) >> 8) as u8,
1557 ((self_array[14] as u16).wrapping_mul(rhs_array[14] as u16) >> 8) as u8,
1558 ((self_array[15] as u16).wrapping_mul(rhs_array[15] as u16) >> 8) as u8,
1559 ])
1560 }
1561 }
1562 }
1563
1564 optional_fn_deserialize {}
1565}
1566
1567impl u8x16 {
1570 #[inline]
1573 #[must_use]
1574 pub fn unpack_low(lhs: u8x16, rhs: u8x16) -> u8x16 {
1575 pick! {
1576 if #[cfg(target_feature = "sse2")] {
1577 u8x16 { sse: unpack_low_i8_m128i(lhs.sse, rhs.sse) }
1578 } else if #[cfg(target_feature = "simd128")] {
1579 u8x16 { simd: u8x16_shuffle::<0, 16, 1, 17, 2, 18, 3, 19, 4, 20, 5, 21, 6, 22, 7, 23>(lhs.simd, rhs.simd) }
1580 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1581 let lhs = unsafe { vget_low_u8(lhs.neon) };
1582 let rhs = unsafe { vget_low_u8(rhs.neon) };
1583
1584 let zipped = unsafe { vzip_u8(lhs, rhs) };
1585 u8x16 { neon: unsafe { vcombine_u8(zipped.0, zipped.1) } }
1586 } else {
1587 u8x16::new([
1588 lhs.as_array()[0], rhs.as_array()[0],
1589 lhs.as_array()[1], rhs.as_array()[1],
1590 lhs.as_array()[2], rhs.as_array()[2],
1591 lhs.as_array()[3], rhs.as_array()[3],
1592 lhs.as_array()[4], rhs.as_array()[4],
1593 lhs.as_array()[5], rhs.as_array()[5],
1594 lhs.as_array()[6], rhs.as_array()[6],
1595 lhs.as_array()[7], rhs.as_array()[7],
1596 ])
1597 }
1598 }
1599 }
1600
1601 #[inline]
1604 #[must_use]
1605 pub fn unpack_high(lhs: u8x16, rhs: u8x16) -> u8x16 {
1606 pick! {
1607 if #[cfg(target_feature = "sse2")] {
1608 u8x16 { sse: unpack_high_i8_m128i(lhs.sse, rhs.sse) }
1609 } else if #[cfg(target_feature = "simd128")] {
1610 u8x16 { simd: u8x16_shuffle::<8, 24, 9, 25, 10, 26, 11, 27, 12, 28, 13, 29, 14, 30, 15, 31>(lhs.simd, rhs.simd) }
1611 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1612 let lhs = unsafe { vget_high_u8(lhs.neon) };
1613 let rhs = unsafe { vget_high_u8(rhs.neon) };
1614
1615 let zipped = unsafe { vzip_u8(lhs, rhs) };
1616 u8x16 { neon: unsafe { vcombine_u8(zipped.0, zipped.1) } }
1617 } else {
1618 u8x16::new([
1619 lhs.as_array()[8], rhs.as_array()[8],
1620 lhs.as_array()[9], rhs.as_array()[9],
1621 lhs.as_array()[10], rhs.as_array()[10],
1622 lhs.as_array()[11], rhs.as_array()[11],
1623 lhs.as_array()[12], rhs.as_array()[12],
1624 lhs.as_array()[13], rhs.as_array()[13],
1625 lhs.as_array()[14], rhs.as_array()[14],
1626 lhs.as_array()[15], rhs.as_array()[15],
1627 ])
1628 }
1629 }
1630 }
1631
1632 #[inline]
1635 #[must_use]
1636 pub fn narrow_i16x8(lhs: i16x8, rhs: i16x8) -> Self {
1637 pick! {
1638 if #[cfg(target_feature = "sse2")] {
1639 u8x16 { sse: pack_i16_to_u8_m128i(lhs.sse, rhs.sse) }
1640 } else if #[cfg(target_feature = "simd128")] {
1641 u8x16 { simd: u8x16_narrow_i16x8(lhs.simd, rhs.simd) }
1642 } else if #[cfg(all(target_feature = "neon", target_arch = "aarch64"))] {
1643 let lhs = unsafe { vqmovun_s16(lhs.neon) };
1644 let rhs = unsafe { vqmovun_s16(rhs.neon) };
1645 u8x16 { neon: unsafe { vcombine_u8(lhs, rhs) } }
1646 } else {
1647 fn clamp(a: i16) -> u8 {
1648 if a < u8::MIN as i16 {
1649 u8::MIN
1650 } else if a > u8::MAX as i16 {
1651 u8::MAX
1652 } else {
1653 a as u8
1654 }
1655 }
1656
1657 Self { arr: [
1658 clamp(lhs.as_array()[0]),
1659 clamp(lhs.as_array()[1]),
1660 clamp(lhs.as_array()[2]),
1661 clamp(lhs.as_array()[3]),
1662 clamp(lhs.as_array()[4]),
1663 clamp(lhs.as_array()[5]),
1664 clamp(lhs.as_array()[6]),
1665 clamp(lhs.as_array()[7]),
1666 clamp(rhs.as_array()[0]),
1667 clamp(rhs.as_array()[1]),
1668 clamp(rhs.as_array()[2]),
1669 clamp(rhs.as_array()[3]),
1670 clamp(rhs.as_array()[4]),
1671 clamp(rhs.as_array()[5]),
1672 clamp(rhs.as_array()[6]),
1673 clamp(rhs.as_array()[7]),
1674 ]}
1675 }
1676 }
1677 }
1678
1679 #[inline]
1690 #[deprecated(since = "1.7.0", note = "replaced with `shuffle_zeroing`")]
1691 pub fn swizzle(self, rhs: i8x16) -> i8x16 {
1692 self.shuffle_zeroing(rhs.cast_unsigned()).cast_signed()
1693 }
1694
1695 #[inline]
1708 #[deprecated(since = "1.7.0", note = "replaced with `shuffle`")]
1709 pub fn swizzle_relaxed(self, rhs: u8x16) -> u8x16 {
1710 self.shuffle(rhs)
1711 }
1712}