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 i16x8 { 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 i16x8 { pub(crate) simd: v128 }
14
15 impl Default for i16x8 {
16 fn default() -> Self {
17 Self::splat(0)
18 }
19 }
20
21 impl PartialEq for i16x8 {
22 fn eq(&self, other: &Self) -> bool {
23 u16x8_all_true(i16x8_eq(self.simd, other.simd))
24 }
25 }
26
27 impl Eq for i16x8 { }
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 i16x8 { pub(crate) neon : int16x8_t }
33
34 impl Default for i16x8 {
35 #[inline]
36 fn default() -> Self {
37 Self::splat(0)
38 }
39 }
40
41 impl PartialEq for i16x8 {
42 #[inline]
43 fn eq(&self, other: &Self) -> bool {
44 unsafe { vminvq_u16(vceqq_s16(self.neon, other.neon))==u16::MAX }
45 }
46 }
47
48 impl Eq for i16x8 { }
49 } else {
50 #[derive(Default, Clone, Copy, PartialEq, Eq)]
51 #[repr(C, align(16))]
52 pub struct i16x8 { pub(crate) arr: [i16;8] }
53 }
54}
55
56int_uint_consts!(i16, 8, i16x8, 128);
57
58unsafe impl Zeroable for i16x8 {}
59unsafe impl Pod for i16x8 {}
60
61impl AlignTo for i16x8 {
62 type Elem = i16;
63}
64
65impl Add for i16x8 {
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_i16_m128i(self.sse, rhs.sse) }
72 } else if #[cfg(target_feature="simd128")] {
73 Self { simd: i16x8_add(self.simd, rhs.simd) }
74 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
75 unsafe { Self { neon: vaddq_s16(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 ]}
87 }
88 }
89 }
90}
91
92impl Sub for i16x8 {
93 type Output = Self;
94 #[inline]
95 fn sub(self, rhs: Self) -> Self::Output {
96 pick! {
97 if #[cfg(target_feature="sse2")] {
98 Self { sse: sub_i16_m128i(self.sse, rhs.sse) }
99 } else if #[cfg(target_feature="simd128")] {
100 Self { simd: i16x8_sub(self.simd, rhs.simd) }
101 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
102 unsafe {Self { neon: vsubq_s16(self.neon, rhs.neon) }}
103 } else {
104 Self { arr: [
105 self.arr[0].wrapping_sub(rhs.arr[0]),
106 self.arr[1].wrapping_sub(rhs.arr[1]),
107 self.arr[2].wrapping_sub(rhs.arr[2]),
108 self.arr[3].wrapping_sub(rhs.arr[3]),
109 self.arr[4].wrapping_sub(rhs.arr[4]),
110 self.arr[5].wrapping_sub(rhs.arr[5]),
111 self.arr[6].wrapping_sub(rhs.arr[6]),
112 self.arr[7].wrapping_sub(rhs.arr[7]),
113 ]}
114 }
115 }
116 }
117}
118
119impl Mul for i16x8 {
120 type Output = Self;
121 #[inline]
122 fn mul(self, rhs: Self) -> Self::Output {
123 pick! {
124 if #[cfg(target_feature="sse2")] {
125 Self { sse: mul_i16_keep_low_m128i(self.sse, rhs.sse) }
126 } else if #[cfg(target_feature="simd128")] {
127 Self { simd: i16x8_mul(self.simd, rhs.simd) }
128 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
129 unsafe {Self { neon: vmulq_s16(self.neon, rhs.neon) }}
130 } else {
131 Self { arr: [
132 self.arr[0].wrapping_mul(rhs.arr[0]),
133 self.arr[1].wrapping_mul(rhs.arr[1]),
134 self.arr[2].wrapping_mul(rhs.arr[2]),
135 self.arr[3].wrapping_mul(rhs.arr[3]),
136 self.arr[4].wrapping_mul(rhs.arr[4]),
137 self.arr[5].wrapping_mul(rhs.arr[5]),
138 self.arr[6].wrapping_mul(rhs.arr[6]),
139 self.arr[7].wrapping_mul(rhs.arr[7]),
140 ]}
141 }
142 }
143 }
144}
145
146integer_impl_div_rem!(i16, i16x8, [0, 1, 2, 3, 4, 5, 6, 7]);
147
148impl Shl for i16x8 {
149 type Output = Self;
150
151 #[inline]
157 fn shl(self, rhs: Self) -> Self::Output {
158 pick! {
159 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
160 #[cfg(target_arch = "x86")]
161 use core::arch::x86::_mm_sllv_epi16;
162 #[cfg(target_arch = "x86_64")]
163 use core::arch::x86_64::_mm_sllv_epi16;
164
165 let rhs = bitand_m128i(rhs.sse, set_splat_i16_m128i(15));
167 cast(unsafe { _mm_sllv_epi16(self.sse.0, rhs.0) })
169 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
170 unsafe {
171 let rhs = vandq_s16(rhs.neon, vmovq_n_s16(15));
173 Self { neon: vshlq_s16(self.neon, rhs) }
174 }
175 } else {
176 let self_array = self.to_array();
177 let rhs_array = rhs.to_array();
178
179 Self::new([
180 self_array[0].wrapping_shl(rhs_array[0] as u32),
181 self_array[1].wrapping_shl(rhs_array[1] as u32),
182 self_array[2].wrapping_shl(rhs_array[2] as u32),
183 self_array[3].wrapping_shl(rhs_array[3] as u32),
184 self_array[4].wrapping_shl(rhs_array[4] as u32),
185 self_array[5].wrapping_shl(rhs_array[5] as u32),
186 self_array[6].wrapping_shl(rhs_array[6] as u32),
187 self_array[7].wrapping_shl(rhs_array[7] as u32),
188 ])
189 }
190 }
191 }
192}
193
194impl Shr for i16x8 {
195 type Output = Self;
196
197 #[inline]
203 fn shr(self, rhs: Self) -> Self::Output {
204 pick! {
205 if #[cfg(all(target_feature="avx512bw", target_feature="avx512vl"))] {
206 #[cfg(target_arch = "x86")]
207 use core::arch::x86::_mm_srav_epi16;
208 #[cfg(target_arch = "x86_64")]
209 use core::arch::x86_64::_mm_srav_epi16;
210
211 let rhs = bitand_m128i(rhs.sse, set_splat_i16_m128i(15));
213 cast(unsafe { _mm_srav_epi16(self.sse.0, rhs.0) })
215 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
216 unsafe {
217 let neg_rhs = vnegq_s16(vandq_s16(rhs.neon, vmovq_n_s16(15)));
220 Self { neon: vshlq_s16(self.neon, neg_rhs) }
221 }
222 } else {
223 let self_array = self.to_array();
224 let rhs_array = rhs.to_array();
225
226 Self::new([
227 self_array[0].wrapping_shr(rhs_array[0] as u32),
228 self_array[1].wrapping_shr(rhs_array[1] as u32),
229 self_array[2].wrapping_shr(rhs_array[2] as u32),
230 self_array[3].wrapping_shr(rhs_array[3] as u32),
231 self_array[4].wrapping_shr(rhs_array[4] as u32),
232 self_array[5].wrapping_shr(rhs_array[5] as u32),
233 self_array[6].wrapping_shr(rhs_array[6] as u32),
234 self_array[7].wrapping_shr(rhs_array[7] as u32),
235 ])
236 }
237 }
238 }
239}
240
241impl Add<i16> for i16x8 {
242 type Output = Self;
243 #[inline]
244 fn add(self, rhs: i16) -> Self::Output {
245 self.add(Self::splat(rhs))
246 }
247}
248
249impl Sub<i16> for i16x8 {
250 type Output = Self;
251 #[inline]
252 fn sub(self, rhs: i16) -> Self::Output {
253 self.sub(Self::splat(rhs))
254 }
255}
256
257impl Mul<i16> for i16x8 {
258 type Output = Self;
259 #[inline]
260 fn mul(self, rhs: i16) -> Self::Output {
261 self.mul(Self::splat(rhs))
262 }
263}
264
265impl Add<i16x8> for i16 {
266 type Output = i16x8;
267 #[inline]
268 fn add(self, rhs: i16x8) -> Self::Output {
269 i16x8::splat(self).add(rhs)
270 }
271}
272
273impl Sub<i16x8> for i16 {
274 type Output = i16x8;
275 #[inline]
276 fn sub(self, rhs: i16x8) -> Self::Output {
277 i16x8::splat(self).sub(rhs)
278 }
279}
280
281impl Mul<i16x8> for i16 {
282 type Output = i16x8;
283 #[inline]
284 fn mul(self, rhs: i16x8) -> Self::Output {
285 i16x8::splat(self).mul(rhs)
286 }
287}
288
289impl BitAnd for i16x8 {
290 type Output = Self;
291 #[inline]
292 fn bitand(self, rhs: Self) -> Self::Output {
293 pick! {
294 if #[cfg(target_feature="sse2")] {
295 Self { sse: bitand_m128i(self.sse, rhs.sse) }
296 } else if #[cfg(target_feature="simd128")] {
297 Self { simd: v128_and(self.simd, rhs.simd) }
298 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
299 unsafe {Self { neon: vandq_s16(self.neon, rhs.neon) }}
300 } else {
301 Self { arr: [
302 self.arr[0].bitand(rhs.arr[0]),
303 self.arr[1].bitand(rhs.arr[1]),
304 self.arr[2].bitand(rhs.arr[2]),
305 self.arr[3].bitand(rhs.arr[3]),
306 self.arr[4].bitand(rhs.arr[4]),
307 self.arr[5].bitand(rhs.arr[5]),
308 self.arr[6].bitand(rhs.arr[6]),
309 self.arr[7].bitand(rhs.arr[7]),
310 ]}
311 }
312 }
313 }
314}
315
316impl BitOr for i16x8 {
317 type Output = Self;
318 #[inline]
319 fn bitor(self, rhs: Self) -> Self::Output {
320 pick! {
321 if #[cfg(target_feature="sse2")] {
322 Self { sse: bitor_m128i(self.sse, rhs.sse) }
323 } else if #[cfg(target_feature="simd128")] {
324 Self { simd: v128_or(self.simd, rhs.simd) }
325 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
326 unsafe {Self { neon: vorrq_s16(self.neon, rhs.neon) }}
327 } else {
328 Self { arr: [
329 self.arr[0].bitor(rhs.arr[0]),
330 self.arr[1].bitor(rhs.arr[1]),
331 self.arr[2].bitor(rhs.arr[2]),
332 self.arr[3].bitor(rhs.arr[3]),
333 self.arr[4].bitor(rhs.arr[4]),
334 self.arr[5].bitor(rhs.arr[5]),
335 self.arr[6].bitor(rhs.arr[6]),
336 self.arr[7].bitor(rhs.arr[7]),
337 ]}
338 }
339 }
340 }
341}
342
343impl BitXor for i16x8 {
344 type Output = Self;
345 #[inline]
346 fn bitxor(self, rhs: Self) -> Self::Output {
347 pick! {
348 if #[cfg(target_feature="sse2")] {
349 Self { sse: bitxor_m128i(self.sse, rhs.sse) }
350 } else if #[cfg(target_feature="simd128")] {
351 Self { simd: v128_xor(self.simd, rhs.simd) }
352 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
353 unsafe {Self { neon: veorq_s16(self.neon, rhs.neon) }}
354 } else {
355 Self { arr: [
356 self.arr[0].bitxor(rhs.arr[0]),
357 self.arr[1].bitxor(rhs.arr[1]),
358 self.arr[2].bitxor(rhs.arr[2]),
359 self.arr[3].bitxor(rhs.arr[3]),
360 self.arr[4].bitxor(rhs.arr[4]),
361 self.arr[5].bitxor(rhs.arr[5]),
362 self.arr[6].bitxor(rhs.arr[6]),
363 self.arr[7].bitxor(rhs.arr[7]),
364 ]}
365 }
366 }
367 }
368}
369
370macro_rules! impl_shl_t_for_i16x8 {
371 ($($shift_type:ty),+ $(,)?) => {
372 $(impl Shl<$shift_type> for i16x8 {
373 type Output = Self;
374 #[inline]
376 fn shl(self, rhs: $shift_type) -> Self::Output {
377 pick! {
378 if #[cfg(target_feature="sse2")] {
379 let shift = cast([rhs as u64, 0]);
380 Self { sse: shl_all_u16_m128i(self.sse, shift) }
381 } else if #[cfg(target_feature="simd128")] {
382 Self { simd: i16x8_shl(self.simd, rhs as u32) }
383 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
384 unsafe {Self { neon: vshlq_s16(self.neon, vmovq_n_s16(rhs as i16)) }}
385 } else {
386 let u = rhs as u32;
387 Self { arr: [
388 self.arr[0].wrapping_shl(u),
389 self.arr[1].wrapping_shl(u),
390 self.arr[2].wrapping_shl(u),
391 self.arr[3].wrapping_shl(u),
392 self.arr[4].wrapping_shl(u),
393 self.arr[5].wrapping_shl(u),
394 self.arr[6].wrapping_shl(u),
395 self.arr[7].wrapping_shl(u),
396 ]}
397 }
398 }
399 }
400 })+
401 };
402}
403impl_shl_t_for_i16x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
404
405macro_rules! impl_shr_t_for_i16x8 {
406 ($($shift_type:ty),+ $(,)?) => {
407 $(impl Shr<$shift_type> for i16x8 {
408 type Output = Self;
409 #[inline]
411 fn shr(self, rhs: $shift_type) -> Self::Output {
412 pick! {
413 if #[cfg(target_feature="sse2")] {
414 let shift = cast([rhs as u64, 0]);
415 Self { sse: shr_all_i16_m128i(self.sse, shift) }
416 } else if #[cfg(target_feature="simd128")] {
417 Self { simd: i16x8_shr(self.simd, rhs as u32) }
418 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
419 unsafe {Self { neon: vshlq_s16(self.neon, vmovq_n_s16( -(rhs as i16))) }}
420 } else {
421 let u = rhs as u32;
422 Self { arr: [
423 self.arr[0].wrapping_shr(u),
424 self.arr[1].wrapping_shr(u),
425 self.arr[2].wrapping_shr(u),
426 self.arr[3].wrapping_shr(u),
427 self.arr[4].wrapping_shr(u),
428 self.arr[5].wrapping_shr(u),
429 self.arr[6].wrapping_shr(u),
430 self.arr[7].wrapping_shr(u),
431 ]}
432 }
433 }
434 }
435 })+
436 };
437}
438impl_shr_t_for_i16x8!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128);
439
440#[expect(deprecated)]
441impl CmpEq for i16x8 {
442 type Output = Self;
443 #[inline]
444 fn simd_eq(self, rhs: Self) -> Self::Output {
445 pick! {
446 if #[cfg(target_feature="sse2")] {
447 Self { sse: cmp_eq_mask_i16_m128i(self.sse, rhs.sse) }
448 } else if #[cfg(target_feature="simd128")] {
449 Self { simd: i16x8_eq(self.simd, rhs.simd) }
450 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
451 unsafe {Self { neon: vreinterpretq_s16_u16(vceqq_s16(self.neon, rhs.neon)) }}
452 } else {
453 Self { arr: [
454 if self.arr[0] == rhs.arr[0] { -1 } else { 0 },
455 if self.arr[1] == rhs.arr[1] { -1 } else { 0 },
456 if self.arr[2] == rhs.arr[2] { -1 } else { 0 },
457 if self.arr[3] == rhs.arr[3] { -1 } else { 0 },
458 if self.arr[4] == rhs.arr[4] { -1 } else { 0 },
459 if self.arr[5] == rhs.arr[5] { -1 } else { 0 },
460 if self.arr[6] == rhs.arr[6] { -1 } else { 0 },
461 if self.arr[7] == rhs.arr[7] { -1 } else { 0 },
462 ]}
463 }
464 }
465 }
466}
467
468#[expect(deprecated)]
469impl CmpGt for i16x8 {
470 type Output = Self;
471 #[inline]
472 fn simd_gt(self, rhs: Self) -> Self::Output {
473 pick! {
474 if #[cfg(target_feature="sse2")] {
475 Self { sse: cmp_gt_mask_i16_m128i(self.sse, rhs.sse) }
476 } else if #[cfg(target_feature="simd128")] {
477 Self { simd: i16x8_gt(self.simd, rhs.simd) }
478 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
479 unsafe {Self { neon: vreinterpretq_s16_u16(vcgtq_s16(self.neon, rhs.neon)) }}
480 } else {
481 Self { arr: [
482 if self.arr[0] > rhs.arr[0] { -1 } else { 0 },
483 if self.arr[1] > rhs.arr[1] { -1 } else { 0 },
484 if self.arr[2] > rhs.arr[2] { -1 } else { 0 },
485 if self.arr[3] > rhs.arr[3] { -1 } else { 0 },
486 if self.arr[4] > rhs.arr[4] { -1 } else { 0 },
487 if self.arr[5] > rhs.arr[5] { -1 } else { 0 },
488 if self.arr[6] > rhs.arr[6] { -1 } else { 0 },
489 if self.arr[7] > rhs.arr[7] { -1 } else { 0 },
490 ]}
491 }
492 }
493 }
494}
495
496#[expect(deprecated)]
497impl CmpLt for i16x8 {
498 type Output = Self;
499 #[inline]
500 fn simd_lt(self, rhs: Self) -> Self::Output {
501 pick! {
502 if #[cfg(target_feature="sse2")] {
503 Self { sse: cmp_lt_mask_i16_m128i(self.sse, rhs.sse) }
504 } else if #[cfg(target_feature="simd128")] {
505 Self { simd: i16x8_lt(self.simd, rhs.simd) }
506 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
507 unsafe {Self { neon: vreinterpretq_s16_u16(vcltq_s16(self.neon, rhs.neon)) }}
508 } else {
509 Self { arr: [
510 if self.arr[0] < rhs.arr[0] { -1 } else { 0 },
511 if self.arr[1] < rhs.arr[1] { -1 } else { 0 },
512 if self.arr[2] < rhs.arr[2] { -1 } else { 0 },
513 if self.arr[3] < rhs.arr[3] { -1 } else { 0 },
514 if self.arr[4] < rhs.arr[4] { -1 } else { 0 },
515 if self.arr[5] < rhs.arr[5] { -1 } else { 0 },
516 if self.arr[6] < rhs.arr[6] { -1 } else { 0 },
517 if self.arr[7] < rhs.arr[7] { -1 } else { 0 },
518 ]}
519 }
520 }
521 }
522}
523
524#[expect(deprecated)]
525impl CmpNe for i16x8 {
526 type Output = Self;
527 #[inline]
528 fn simd_ne(self, rhs: Self) -> Self::Output {
529 pick! {
530 if #[cfg(target_feature="sse2")] {
531 !self.simd_eq(rhs)
532 } else if #[cfg(target_feature="simd128")] {
533 Self { simd: i16x8_ne(self.simd, rhs.simd) }
534 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
535 !self.simd_eq(rhs)
536 } else {
537 Self { arr: [
538 if self.arr[0] != rhs.arr[0] { -1 } else { 0 },
539 if self.arr[1] != rhs.arr[1] { -1 } else { 0 },
540 if self.arr[2] != rhs.arr[2] { -1 } else { 0 },
541 if self.arr[3] != rhs.arr[3] { -1 } else { 0 },
542 if self.arr[4] != rhs.arr[4] { -1 } else { 0 },
543 if self.arr[5] != rhs.arr[5] { -1 } else { 0 },
544 if self.arr[6] != rhs.arr[6] { -1 } else { 0 },
545 if self.arr[7] != rhs.arr[7] { -1 } else { 0 },
546 ]}
547 }
548 }
549 }
550}
551
552#[expect(deprecated)]
553impl CmpLe for i16x8 {
554 type Output = Self;
555 #[inline]
556 fn simd_le(self, rhs: Self) -> Self::Output {
557 pick! {
558 if #[cfg(target_feature="sse2")] {
559 !self.simd_gt(rhs)
560 } else if #[cfg(target_feature="simd128")] {
561 Self { simd: i16x8_le(self.simd, rhs.simd) }
562 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
563 !self.simd_gt(rhs)
564 } else {
565 Self { arr: [
566 if self.arr[0] <= rhs.arr[0] { -1 } else { 0 },
567 if self.arr[1] <= rhs.arr[1] { -1 } else { 0 },
568 if self.arr[2] <= rhs.arr[2] { -1 } else { 0 },
569 if self.arr[3] <= rhs.arr[3] { -1 } else { 0 },
570 if self.arr[4] <= rhs.arr[4] { -1 } else { 0 },
571 if self.arr[5] <= rhs.arr[5] { -1 } else { 0 },
572 if self.arr[6] <= rhs.arr[6] { -1 } else { 0 },
573 if self.arr[7] <= rhs.arr[7] { -1 } else { 0 },
574 ]}
575 }
576 }
577 }
578}
579
580#[expect(deprecated)]
581impl CmpGe for i16x8 {
582 type Output = Self;
583 #[inline]
584 fn simd_ge(self, rhs: Self) -> Self::Output {
585 pick! {
586 if #[cfg(target_feature="sse2")] {
587 !self.simd_lt(rhs)
588 } else if #[cfg(target_feature="simd128")] {
589 Self { simd: i16x8_ge(self.simd, rhs.simd) }
590 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
591 !self.simd_lt(rhs)
592 } else {
593 Self { arr: [
594 if self.arr[0] >= rhs.arr[0] { -1 } else { 0 },
595 if self.arr[1] >= rhs.arr[1] { -1 } else { 0 },
596 if self.arr[2] >= rhs.arr[2] { -1 } else { 0 },
597 if self.arr[3] >= rhs.arr[3] { -1 } else { 0 },
598 if self.arr[4] >= rhs.arr[4] { -1 } else { 0 },
599 if self.arr[5] >= rhs.arr[5] { -1 } else { 0 },
600 if self.arr[6] >= rhs.arr[6] { -1 } else { 0 },
601 if self.arr[7] >= rhs.arr[7] { -1 } else { 0 },
602 ]}
603 }
604 }
605 }
606}
607
608impl i16x8 {
609 #[inline]
610 #[must_use]
611 pub const fn new(array: [i16; 8]) -> Self {
612 unsafe { core::mem::transmute(array) }
613 }
614
615 simd_comparison_fns!();
616
617 #[inline]
618 #[must_use]
619 #[doc(alias("movemask", "move_mask"))]
620 pub fn to_bitmask(self) -> u32 {
621 pick! {
622 if #[cfg(target_feature="sse2")] {
623 (move_mask_i8_m128i( pack_i16_to_i8_m128i(self.sse,self.sse)) as u32) & 0xff
624 } else if #[cfg(target_feature="simd128")] {
625 i16x8_bitmask(self.simd) as u32
626 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
627 unsafe
628 {
629 let masked = vcltq_s16(self.neon, vdupq_n_s16(0));
631
632 let selectbit : uint16x8_t = core::mem::transmute([1u16, 2, 4, 8, 16, 32, 64, 128]);
634 let r = vandq_u16(masked, selectbit);
635
636 vaddvq_u16(r) as u32
638 }
639 } else {
640 ((self.arr[0] < 0) as u32) << 0 |
641 ((self.arr[1] < 0) as u32) << 1 |
642 ((self.arr[2] < 0) as u32) << 2 |
643 ((self.arr[3] < 0) as u32) << 3 |
644 ((self.arr[4] < 0) as u32) << 4 |
645 ((self.arr[5] < 0) as u32) << 5 |
646 ((self.arr[6] < 0) as u32) << 6 |
647 ((self.arr[7] < 0) as u32) << 7
648 }
649 }
650 }
651
652 #[inline]
653 #[must_use]
654 pub fn any(self) -> bool {
655 pick! {
656 if #[cfg(target_feature="sse2")] {
657 (move_mask_i8_m128i(self.sse) & 0b1010101010101010) != 0
658 } else if #[cfg(target_feature="simd128")] {
659 u16x8_bitmask(self.simd) != 0
660 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
661 unsafe {
662 vminvq_s16(self.neon) < 0
663 }
664 } else {
665 let v : [u64;2] = cast(self);
666 ((v[0] | v[1]) & 0x8000800080008000) != 0
667 }
668 }
669 }
670
671 #[inline]
672 #[must_use]
673 pub fn all(self) -> bool {
674 pick! {
675 if #[cfg(target_feature="sse2")] {
676 (move_mask_i8_m128i(self.sse) & 0b1010101010101010) == 0b1010101010101010
677 } else if #[cfg(target_feature="simd128")] {
678 u16x8_bitmask(self.simd) == 0b11111111
679 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
680 unsafe {
681 vmaxvq_s16(self.neon) < 0
682 }
683 } else {
684 let v : [u64;2] = cast(self);
685 (v[0] & v[1] & 0x8000800080008000) == 0x8000800080008000
686 }
687 }
688 }
689
690 #[inline]
691 #[must_use]
692 pub fn none(self) -> bool {
693 !self.any()
694 }
695
696 #[inline]
698 #[must_use]
699 pub fn from_u8x16_low(u: u8x16) -> Self {
700 pick! {
701 if #[cfg(target_feature="sse2")] {
702 Self{ sse: unpack_low_i8_m128i(u.sse, m128i::zeroed()) }
703 } else {
704 let u_arr: [u8; 16] = cast(u);
705 cast([
706 u_arr[0] as u16 as i16,
707 u_arr[1] as u16 as i16,
708 u_arr[2] as u16 as i16,
709 u_arr[3] as u16 as i16,
710 u_arr[4] as u16 as i16,
711 u_arr[5] as u16 as i16,
712 u_arr[6] as u16 as i16,
713 u_arr[7] as u16 as i16,
714 ])
715 }
716 }
717 }
718
719 #[inline]
721 #[must_use]
722 pub fn from_u8x16_high(u: u8x16) -> Self {
723 pick! {
724 if #[cfg(target_feature="sse2")] {
725 Self{ sse: unpack_high_i8_m128i(u.sse, m128i::zeroed()) }
726 } else {
727 let u_arr: [u8; 16] = cast(u);
728 cast([
729 u_arr[8] as u16 as i16,
730 u_arr[9] as u16 as i16,
731 u_arr[10] as u16 as i16,
732 u_arr[11] as u16 as i16,
733 u_arr[12] as u16 as i16,
734 u_arr[13] as u16 as i16,
735 u_arr[14] as u16 as i16,
736 u_arr[15] as u16 as i16,
737 ])
738 }
739 }
740 }
741
742 #[inline]
744 #[must_use]
745 pub fn from_i32x8_saturate(v: i32x8) -> Self {
746 pick! {
747 if #[cfg(target_feature="avx2")] {
748 i16x8 { sse: pack_i32_to_i16_m128i( extract_m128i_from_m256i::<0>(v.avx2), extract_m128i_from_m256i::<1>(v.avx2)) }
749 } else if #[cfg(target_feature="sse2")] {
750 i16x8 { sse: pack_i32_to_i16_m128i( v.a.sse, v.b.sse ) }
751 } else if #[cfg(target_feature="simd128")] {
752 use core::arch::wasm32::*;
753
754 i16x8 { simd: i16x8_narrow_i32x4(v.a.simd, v.b.simd) }
755 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
756 use core::arch::aarch64::*;
757
758 unsafe {
759 i16x8 { neon: vcombine_s16(vqmovn_s32(v.a.neon), vqmovn_s32(v.b.neon)) }
760 }
761 } else {
762 fn clamp(a : i32) -> i16 {
763 if a < i16::MIN as i32 {
764 i16::MIN
765 }
766 else if a > i16::MAX as i32 {
767 i16::MAX
768 } else {
769 a as i16
770 }
771 }
772
773 i16x8::new([
774 clamp(v.as_array()[0]),
775 clamp(v.as_array()[1]),
776 clamp(v.as_array()[2]),
777 clamp(v.as_array()[3]),
778 clamp(v.as_array()[4]),
779 clamp(v.as_array()[5]),
780 clamp(v.as_array()[6]),
781 clamp(v.as_array()[7]),
782 ])
783 }
784 }
785 }
786
787 #[inline]
789 #[must_use]
790 pub fn from_i32x8_truncate(v: i32x8) -> Self {
791 pick! {
792 if #[cfg(target_feature="avx2")] {
793 let a = v.avx2.bitand(set_splat_i32_m256i(0xffff));
794 i16x8 { sse: pack_i32_to_u16_m128i( extract_m128i_from_m256i::<0>(a), extract_m128i_from_m256i::<1>(a) ) }
795 } else if #[cfg(target_feature="sse2")] {
796 let a = shr_imm_i32_m128i::<16>(shl_imm_u32_m128i::<16>(v.a.sse));
797 let b = shr_imm_i32_m128i::<16>(shl_imm_u32_m128i::<16>(v.b.sse));
798
799 i16x8 { sse: pack_i32_to_i16_m128i( a, b) }
800 } else {
801 i16x8::new([
802 v.as_array()[0] as i16,
803 v.as_array()[1] as i16,
804 v.as_array()[2] as i16,
805 v.as_array()[3] as i16,
806 v.as_array()[4] as i16,
807 v.as_array()[5] as i16,
808 v.as_array()[6] as i16,
809 v.as_array()[7] as i16,
810 ])
811 }
812 }
813 }
814
815 #[inline]
816 #[must_use]
817 pub fn from_slice_unaligned(input: &[i16]) -> Self {
818 assert!(input.len() >= 8);
819
820 pick! {
821 if #[cfg(target_feature="sse2")] {
822 unsafe { Self { sse: load_unaligned_m128i( &*(input.as_ptr() as * const [u8;16]) ) } }
823 } else if #[cfg(target_feature="simd128")] {
824 unsafe { Self { simd: v128_load(input.as_ptr() as *const v128 ) } }
825 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
826 unsafe { Self { neon: vld1q_s16( input.as_ptr() as *const i16 ) } }
827 } else {
828 unsafe { Self::new( *(input.as_ptr() as * const [i16;8]) ) }
830 }
831 }
832 }
833
834 #[inline]
835 #[must_use]
836 pub fn blend(self, t: Self, f: Self) -> Self {
837 pick! {
838 if #[cfg(target_feature="sse4.1")] {
839 Self { sse: blend_varying_i8_m128i(f.sse, t.sse, self.sse) }
840 } else if #[cfg(target_feature="simd128")] {
841 Self { simd: v128_bitselect(t.simd, f.simd, self.simd) }
842 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
843 unsafe {Self { neon: vbslq_s16(vreinterpretq_u16_s16(self.neon), t.neon, f.neon) }}
844 } else {
845 generic_bit_blend(self, t, f)
846 }
847 }
848 }
849
850 #[inline]
853 #[must_use]
854 pub fn is_positive(self) -> Self {
855 pick! {
856 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
857 Self { neon: unsafe { vreinterpretq_s16_u16(vcgtzq_s16(self.neon)) } }
858 } else {
859 self.simd_gt(Self::ZERO)
860 }
861 }
862 }
863
864 #[inline]
867 #[must_use]
868 pub fn is_negative(self) -> Self {
869 pick! {
870 if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
871 Self { neon: unsafe { vreinterpretq_s16_u16(vcltzq_s16(self.neon)) } }
872 } else {
873 self.simd_lt(Self::ZERO)
874 }
875 }
876 }
877
878 #[inline]
880 #[must_use]
881 pub fn reduce_add(self) -> i16 {
882 pick! {
883 if #[cfg(target_feature="sse2")] {
884 let hi64 = shuffle_ai_f32_all_m128i::<0b01_00_11_10>(self.sse);
886 let sum64 = add_i16_m128i(self.sse, hi64);
887 let hi32 = shuffle_ai_f32_all_m128i::<0b11_10_00_01>(sum64);
888 let sum32 = add_i16_m128i(sum64, hi32);
889 let lo16 = shr_imm_u32_m128i::<16>(sum32);
890 let sum16 = add_i16_m128i(sum32, lo16);
891 extract_i16_as_i32_m128i::<0>(sum16) as i16
892 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
893 unsafe { vaddvq_s16(self.neon) }
894 } else {
895 let arr: [i16; 8] = cast(self);
896
897 let mut r = arr[0];
899 r = r.wrapping_add(arr[1]);
900 r = r.wrapping_add(arr[2]);
901 r = r.wrapping_add(arr[3]);
902 r = r.wrapping_add(arr[4]);
903 r = r.wrapping_add(arr[5]);
904 r = r.wrapping_add(arr[6]);
905 r.wrapping_add(arr[7])
906 }
907 }
908 }
909
910 #[inline]
912 #[must_use]
913 pub fn reduce_min(self) -> i16 {
914 pick! {
915 if #[cfg(target_feature="sse2")] {
916 let hi64 = shuffle_ai_f32_all_m128i::<0b01_00_11_10>(self.sse);
917 let sum64 = min_i16_m128i(self.sse, hi64);
918 let hi32 = shuffle_ai_f32_all_m128i::<0b11_10_00_01>(sum64);
919 let sum32 = min_i16_m128i(sum64, hi32);
920 let lo16 = shr_imm_u32_m128i::<16>(sum32);
921 let sum16 = min_i16_m128i(sum32, lo16);
922 extract_i16_as_i32_m128i::<0>(sum16) as i16
923 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
924 unsafe { vminvq_s16(self.neon) }
925 } else {
926 let arr: [i16; 8] = cast(self);
927
928 let mut r = arr[0];
930 r = r.min(arr[1]);
931 r = r.min(arr[2]);
932 r = r.min(arr[3]);
933 r = r.min(arr[4]);
934 r = r.min(arr[5]);
935 r = r.min(arr[6]);
936 r.min(arr[7])
937 }
938 }
939 }
940
941 #[inline]
943 #[must_use]
944 pub fn reduce_max(self) -> i16 {
945 pick! {
946 if #[cfg(target_feature="sse2")] {
947 let hi64 = shuffle_ai_f32_all_m128i::<0b01_00_11_10>(self.sse);
948 let sum64 = max_i16_m128i(self.sse, hi64);
949 let hi32 = shuffle_ai_f32_all_m128i::<0b11_10_00_01>(sum64);
950 let sum32 = max_i16_m128i(sum64, hi32);
951 let lo16 = shr_imm_u32_m128i::<16>(sum32);
952 let sum16 = max_i16_m128i(sum32, lo16);
953 extract_i16_as_i32_m128i::<0>(sum16) as i16
954 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
955 unsafe { vmaxvq_s16(self.neon) }
956 } else {
957 let arr: [i16; 8] = cast(self);
958
959 let mut r = arr[0];
961 r = r.max(arr[1]);
962 r = r.max(arr[2]);
963 r = r.max(arr[3]);
964 r = r.max(arr[4]);
965 r = r.max(arr[5]);
966 r = r.max(arr[6]);
967 r.max(arr[7])
968 }
969 }
970 }
971
972 #[inline]
973 #[must_use]
974 pub fn abs(self) -> Self {
975 pick! {
976 if #[cfg(target_feature="sse2")] {
977 let mask = shr_imm_i16_m128i::<15>(self.sse);
978 Self { sse: bitxor_m128i(add_i16_m128i(self.sse, mask), mask) }
979 } else if #[cfg(target_feature="ssse3")] {
980 Self { sse: abs_i16_m128i(self.sse) }
981 } else if #[cfg(target_feature="simd128")] {
982 Self { simd: i16x8_abs(self.simd) }
983 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
984 unsafe {Self { neon: vabsq_s16(self.neon) }}
985 } else {
986 let arr: [i16; 8] = cast(self);
987 cast(
988 [
989 arr[0].wrapping_abs(),
990 arr[1].wrapping_abs(),
991 arr[2].wrapping_abs(),
992 arr[3].wrapping_abs(),
993 arr[4].wrapping_abs(),
994 arr[5].wrapping_abs(),
995 arr[6].wrapping_abs(),
996 arr[7].wrapping_abs(),
997 ])
998 }
999 }
1000 }
1001
1002 #[inline]
1003 #[must_use]
1004 pub fn unsigned_abs(self) -> u16x8 {
1005 pick! {
1006 if #[cfg(target_feature="sse2")] {
1007 let mask = shr_imm_i16_m128i::<15>(self.sse);
1008 u16x8 { sse: bitxor_m128i(add_i16_m128i(self.sse, mask), mask) }
1009 } else if #[cfg(target_feature="ssse3")] {
1010 u16x8 { sse: abs_i16_m128i(self.sse) }
1011 } else if #[cfg(target_feature="simd128")] {
1012 u16x8 { simd: i16x8_abs(self.simd) }
1013 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1014 unsafe {u16x8 { neon: vreinterpretq_u16_s16(vabsq_s16(self.neon)) }}
1015 } else {
1016 let arr: [i16; 8] = cast(self);
1017 cast(
1018 [
1019 arr[0].unsigned_abs(),
1020 arr[1].unsigned_abs(),
1021 arr[2].unsigned_abs(),
1022 arr[3].unsigned_abs(),
1023 arr[4].unsigned_abs(),
1024 arr[5].unsigned_abs(),
1025 arr[6].unsigned_abs(),
1026 arr[7].unsigned_abs(),
1027 ])
1028 }
1029 }
1030 }
1031
1032 signed_fn_signum!();
1033
1034 #[inline]
1035 #[must_use]
1036 pub fn max(self, rhs: Self) -> Self {
1037 pick! {
1038 if #[cfg(target_feature="sse2")] {
1039 Self { sse: max_i16_m128i(self.sse, rhs.sse) }
1040 } else if #[cfg(target_feature="simd128")] {
1041 Self { simd: i16x8_max(self.simd, rhs.simd) }
1042 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1043 unsafe {Self { neon: vmaxq_s16(self.neon, rhs.neon) }}
1044 } else {
1045 self.simd_lt(rhs).blend(rhs, self)
1046 }
1047 }
1048 }
1049 #[inline]
1050 #[must_use]
1051 pub fn min(self, rhs: Self) -> Self {
1052 pick! {
1053 if #[cfg(target_feature="sse2")] {
1054 Self { sse: min_i16_m128i(self.sse, rhs.sse) }
1055 } else if #[cfg(target_feature="simd128")] {
1056 Self { simd: i16x8_min(self.simd, rhs.simd) }
1057 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1058 unsafe {Self { neon: vminq_s16(self.neon, rhs.neon) }}
1059 } else {
1060 self.simd_lt(rhs).blend(self, rhs)
1061 }
1062 }
1063 }
1064
1065 integer_fn_clamp!();
1066
1067 #[inline]
1068 #[must_use]
1069 pub fn saturating_add(self, rhs: Self) -> Self {
1070 pick! {
1071 if #[cfg(target_feature="sse2")] {
1072 Self { sse: add_saturating_i16_m128i(self.sse, rhs.sse) }
1073 } else if #[cfg(target_feature="simd128")] {
1074 Self { simd: i16x8_add_sat(self.simd, rhs.simd) }
1075 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1076 unsafe {Self { neon: vqaddq_s16(self.neon, rhs.neon) }}
1077 } else {
1078 Self { arr: [
1079 self.arr[0].saturating_add(rhs.arr[0]),
1080 self.arr[1].saturating_add(rhs.arr[1]),
1081 self.arr[2].saturating_add(rhs.arr[2]),
1082 self.arr[3].saturating_add(rhs.arr[3]),
1083 self.arr[4].saturating_add(rhs.arr[4]),
1084 self.arr[5].saturating_add(rhs.arr[5]),
1085 self.arr[6].saturating_add(rhs.arr[6]),
1086 self.arr[7].saturating_add(rhs.arr[7]),
1087 ]}
1088 }
1089 }
1090 }
1091 #[inline]
1092 #[must_use]
1093 pub fn saturating_sub(self, rhs: Self) -> Self {
1094 pick! {
1095 if #[cfg(target_feature="sse2")] {
1096 Self { sse: sub_saturating_i16_m128i(self.sse, rhs.sse) }
1097 } else if #[cfg(target_feature="simd128")] {
1098 Self { simd: i16x8_sub_sat(self.simd, rhs.simd) }
1099 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1100 unsafe { Self { neon: vqsubq_s16(self.neon, rhs.neon) } }
1101 } else {
1102 Self { arr: [
1103 self.arr[0].saturating_sub(rhs.arr[0]),
1104 self.arr[1].saturating_sub(rhs.arr[1]),
1105 self.arr[2].saturating_sub(rhs.arr[2]),
1106 self.arr[3].saturating_sub(rhs.arr[3]),
1107 self.arr[4].saturating_sub(rhs.arr[4]),
1108 self.arr[5].saturating_sub(rhs.arr[5]),
1109 self.arr[6].saturating_sub(rhs.arr[6]),
1110 self.arr[7].saturating_sub(rhs.arr[7]),
1111 ]}
1112 }
1113 }
1114 }
1115
1116 #[inline]
1118 #[must_use]
1119 pub fn saturating_mul(self, rhs: Self) -> Self {
1120 pick! {
1121 if #[cfg(target_feature="simd128")] {
1122 let low_wide_mul = i32x4_extmul_low_i16x8(self.simd, rhs.simd);
1123 let high_wide_mul = i32x4_extmul_high_i16x8(self.simd, rhs.simd);
1124 let low = Self { simd: i16x8_shuffle::<0, 2, 4, 6, 8, 10, 12, 14>(low_wide_mul, high_wide_mul) };
1125 let high = Self { simd: i16x8_shuffle::<1, 3, 5, 7, 9, 11, 13, 15>(low_wide_mul, high_wide_mul) };
1126
1127 let no_overflow = high.simd_eq(low.is_negative());
1128 let limit = Self::MAX ^ (self ^ rhs).is_negative();
1129 no_overflow.blend(low, limit)
1130 } else if #[cfg(all(target_feature="neon", target_arch="aarch64"))] {
1131 unsafe {
1132 let low_wide_mul = vreinterpretq_s16_s32(
1133 vmull_s16(vget_low_s16(self.neon), vget_low_s16(rhs.neon)),
1134 );
1135 let high_wide_mul = vreinterpretq_s16_s32(
1136 vmull_s16(vget_high_s16(self.neon), vget_high_s16(rhs.neon)),
1137 );
1138 let low_high = vuzpq_s16(low_wide_mul, high_wide_mul);
1139 let low = Self { neon: low_high.0 };
1140 let high = Self { neon: low_high.1 };
1141
1142 let no_overflow = high.simd_eq(low.is_negative());
1143 let limit = Self::MAX ^ (self ^ rhs).is_negative();
1144 no_overflow.blend(low, limit)
1145 }
1146 } else {
1147 let self_array = self.to_array();
1148 let rhs_array = rhs.to_array();
1149
1150 Self::new([
1151 self_array[0].saturating_mul(rhs_array[0]),
1152 self_array[1].saturating_mul(rhs_array[1]),
1153 self_array[2].saturating_mul(rhs_array[2]),
1154 self_array[3].saturating_mul(rhs_array[3]),
1155 self_array[4].saturating_mul(rhs_array[4]),
1156 self_array[5].saturating_mul(rhs_array[5]),
1157 self_array[6].saturating_mul(rhs_array[6]),
1158 self_array[7].saturating_mul(rhs_array[7]),
1159 ])
1160 }
1161 }
1162 }
1163
1164 integer_fn_saturating_div!([0, 1, 2, 3, 4, 5, 6, 7]);
1165
1166 #[inline]
1171 #[must_use]
1172 pub fn dot(self, rhs: Self) -> i32x4 {
1173 pick! {
1174 if #[cfg(target_feature="sse2")] {
1175 i32x4 { sse: mul_i16_horizontal_add_m128i(self.sse, rhs.sse) }
1176 } else if #[cfg(target_feature="simd128")] {
1177 i32x4 { simd: i32x4_dot_i16x8(self.simd, rhs.simd) }
1178 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1179 unsafe {
1180 let pl = vmull_s16(vget_low_s16(self.neon), vget_low_s16(rhs.neon));
1181 let ph = vmull_high_s16(self.neon, rhs.neon);
1182 i32x4 { neon: vpaddq_s32(pl, ph) }
1183 }
1184 } else {
1185 i32x4 { arr: [
1186 (i32::from(self.arr[0]) * i32::from(rhs.arr[0])) + (i32::from(self.arr[1]) * i32::from(rhs.arr[1])),
1187 (i32::from(self.arr[2]) * i32::from(rhs.arr[2])) + (i32::from(self.arr[3]) * i32::from(rhs.arr[3])),
1188 (i32::from(self.arr[4]) * i32::from(rhs.arr[4])) + (i32::from(self.arr[5]) * i32::from(rhs.arr[5])),
1189 (i32::from(self.arr[6]) * i32::from(rhs.arr[6])) + (i32::from(self.arr[7]) * i32::from(rhs.arr[7])),
1190 ] }
1191 }
1192 }
1193 }
1194
1195 #[inline]
1203 #[must_use]
1204 pub fn mul_scale_round(self, rhs: Self) -> Self {
1205 pick! {
1206 if #[cfg(target_feature="ssse3")] {
1207 Self { sse: mul_i16_scale_round_m128i(self.sse, rhs.sse) }
1208 } else if #[cfg(target_feature="sse2")] {
1209 let hi = mul_i16_keep_high_m128i(self.sse, rhs.sse);
1211 let lo = mul_i16_keep_low_m128i(self.sse, rhs.sse);
1212 let mut v1 = unpack_low_i16_m128i(lo, hi);
1213 let mut v2 = unpack_high_i16_m128i(lo, hi);
1214 let a = set_splat_i32_m128i(0x4000);
1215 v1 = shr_imm_i32_m128i::<15>(add_i32_m128i(v1, a));
1216 v2 = shr_imm_i32_m128i::<15>(add_i32_m128i(v2, a));
1217 let s = pack_i32_to_i16_m128i(v1, v2);
1218 Self { sse: s }
1219 } else if #[cfg(target_feature="simd128")] {
1220 Self { simd: i16x8_q15mulr_sat(self.simd, rhs.simd) }
1221 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1222 unsafe { Self { neon: vqrdmulhq_s16(self.neon, rhs.neon) } }
1223 } else {
1224 Self { arr: [
1226 ((i32::from(self.arr[0]) * i32::from(rhs.arr[0]) + 0x4000) >> 15) as i16,
1227 ((i32::from(self.arr[1]) * i32::from(rhs.arr[1]) + 0x4000) >> 15) as i16,
1228 ((i32::from(self.arr[2]) * i32::from(rhs.arr[2]) + 0x4000) >> 15) as i16,
1229 ((i32::from(self.arr[3]) * i32::from(rhs.arr[3]) + 0x4000) >> 15) as i16,
1230 ((i32::from(self.arr[4]) * i32::from(rhs.arr[4]) + 0x4000) >> 15) as i16,
1231 ((i32::from(self.arr[5]) * i32::from(rhs.arr[5]) + 0x4000) >> 15) as i16,
1232 ((i32::from(self.arr[6]) * i32::from(rhs.arr[6]) + 0x4000) >> 15) as i16,
1233 ((i32::from(self.arr[7]) * i32::from(rhs.arr[7]) + 0x4000) >> 15) as i16,
1234 ]}
1235 }
1236 }
1237 }
1238
1239 #[inline]
1241 #[must_use]
1242 pub fn mul_keep_high(lhs: Self, rhs: Self) -> Self {
1243 pick! {
1244 if #[cfg(target_feature="sse2")] {
1245 Self { sse: mul_i16_keep_high_m128i(lhs.sse, rhs.sse) }
1246 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1247 let lhs_low = unsafe { vget_low_s16(lhs.neon) };
1248 let rhs_low = unsafe { vget_low_s16(rhs.neon) };
1249
1250 let lhs_high = unsafe { vget_high_s16(lhs.neon) };
1251 let rhs_high = unsafe { vget_high_s16(rhs.neon) };
1252
1253 let low = unsafe { vmull_s16(lhs_low, rhs_low) };
1254 let high = unsafe { vmull_s16(lhs_high, rhs_high) };
1255
1256 i16x8 { neon: unsafe { vreinterpretq_s16_u16(vuzpq_u16(vreinterpretq_u16_s32(low), vreinterpretq_u16_s32(high)).1) } }
1257 } else if #[cfg(target_feature="simd128")] {
1258 let low = i32x4_extmul_low_i16x8(lhs.simd, rhs.simd);
1259 let high = i32x4_extmul_high_i16x8(lhs.simd, rhs.simd);
1260
1261 Self { simd: i16x8_shuffle::<1, 3, 5, 7, 9, 11, 13, 15>(low, high) }
1262 } else {
1263 i16x8::new([
1264 ((i32::from(rhs.as_array()[0]) * i32::from(lhs.as_array()[0])) >> 16) as i16,
1265 ((i32::from(rhs.as_array()[1]) * i32::from(lhs.as_array()[1])) >> 16) as i16,
1266 ((i32::from(rhs.as_array()[2]) * i32::from(lhs.as_array()[2])) >> 16) as i16,
1267 ((i32::from(rhs.as_array()[3]) * i32::from(lhs.as_array()[3])) >> 16) as i16,
1268 ((i32::from(rhs.as_array()[4]) * i32::from(lhs.as_array()[4])) >> 16) as i16,
1269 ((i32::from(rhs.as_array()[5]) * i32::from(lhs.as_array()[5])) >> 16) as i16,
1270 ((i32::from(rhs.as_array()[6]) * i32::from(lhs.as_array()[6])) >> 16) as i16,
1271 ((i32::from(rhs.as_array()[7]) * i32::from(lhs.as_array()[7])) >> 16) as i16,
1272 ])
1273 }
1274 }
1275 }
1276
1277 #[inline]
1279 #[must_use]
1280 pub fn mul_widen(self, rhs: Self) -> i32x8 {
1281 pick! {
1282 if #[cfg(target_feature="avx2")] {
1283 let a = convert_to_i32_m256i_from_i16_m128i(self.sse);
1284 let b = convert_to_i32_m256i_from_i16_m128i(rhs.sse);
1285 i32x8 { avx2: mul_i32_keep_low_m256i(a,b) }
1286 } else if #[cfg(target_feature="sse2")] {
1287 let low = mul_i16_keep_low_m128i(self.sse, rhs.sse);
1288 let high = mul_i16_keep_high_m128i(self.sse, rhs.sse);
1289 i32x8 {
1290 a: i32x4 { sse:unpack_low_i16_m128i(low, high) },
1291 b: i32x4 { sse:unpack_high_i16_m128i(low, high) }
1292 }
1293 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))] {
1294 let lhs_low = unsafe { vget_low_s16(self.neon) };
1295 let rhs_low = unsafe { vget_low_s16(rhs.neon) };
1296
1297 let lhs_high = unsafe { vget_high_s16(self.neon) };
1298 let rhs_high = unsafe { vget_high_s16(rhs.neon) };
1299
1300 let low = unsafe { vmull_s16(lhs_low, rhs_low) };
1301 let high = unsafe { vmull_s16(lhs_high, rhs_high) };
1302
1303 i32x8 { a: i32x4 { neon: low }, b: i32x4 {neon: high } }
1304 } else {
1305 let a = self.as_array();
1306 let b = rhs.as_array();
1307 i32x8::new([
1308 i32::from(a[0]) * i32::from(b[0]),
1309 i32::from(a[1]) * i32::from(b[1]),
1310 i32::from(a[2]) * i32::from(b[2]),
1311 i32::from(a[3]) * i32::from(b[3]),
1312 i32::from(a[4]) * i32::from(b[4]),
1313 i32::from(a[5]) * i32::from(b[5]),
1314 i32::from(a[6]) * i32::from(b[6]),
1315 i32::from(a[7]) * i32::from(b[7]),
1316 ])
1317 }
1318 }
1319 }
1320
1321 #[must_use]
1323 #[inline]
1324 pub fn transpose(data: [i16x8; 8]) -> [i16x8; 8] {
1325 pick! {
1326 if #[cfg(target_feature="sse2")] {
1327 let a1 = unpack_low_i16_m128i(data[0].sse, data[1].sse);
1328 let a2 = unpack_high_i16_m128i(data[0].sse, data[1].sse);
1329 let a3 = unpack_low_i16_m128i(data[2].sse, data[3].sse);
1330 let a4 = unpack_high_i16_m128i(data[2].sse, data[3].sse);
1331 let a5 = unpack_low_i16_m128i(data[4].sse, data[5].sse);
1332 let a6 = unpack_high_i16_m128i(data[4].sse, data[5].sse);
1333 let a7 = unpack_low_i16_m128i(data[6].sse, data[7].sse);
1334 let a8 = unpack_high_i16_m128i(data[6].sse, data[7].sse);
1335
1336 let b1 = unpack_low_i32_m128i(a1, a3);
1337 let b2 = unpack_high_i32_m128i(a1, a3);
1338 let b3 = unpack_low_i32_m128i(a2, a4);
1339 let b4 = unpack_high_i32_m128i(a2, a4);
1340 let b5 = unpack_low_i32_m128i(a5, a7);
1341 let b6 = unpack_high_i32_m128i(a5, a7);
1342 let b7 = unpack_low_i32_m128i(a6, a8);
1343 let b8 = unpack_high_i32_m128i(a6, a8);
1344
1345 [
1346 i16x8 { sse: unpack_low_i64_m128i(b1, b5) },
1347 i16x8 { sse: unpack_high_i64_m128i(b1, b5) },
1348 i16x8 { sse: unpack_low_i64_m128i(b2, b6) },
1349 i16x8 { sse: unpack_high_i64_m128i(b2, b6) },
1350 i16x8 { sse: unpack_low_i64_m128i(b3, b7) },
1351 i16x8 { sse: unpack_high_i64_m128i(b3, b7) },
1352 i16x8 { sse: unpack_low_i64_m128i(b4, b8) },
1353 i16x8 { sse: unpack_high_i64_m128i(b4, b8) } ,
1354 ]
1355 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1356
1357 #[inline] fn vtrq32(a : int16x8_t, b : int16x8_t) -> (int16x8_t, int16x8_t)
1358 {
1359 unsafe {
1360 let r = vtrnq_s32(vreinterpretq_s32_s16(a),vreinterpretq_s32_s16(b));
1361 (vreinterpretq_s16_s32(r.0), vreinterpretq_s16_s32(r.1))
1362 }
1363 }
1364
1365 unsafe {
1366 let (q0,q2) = vtrq32(data[0].neon, data[2].neon);
1367 let (q1,q3) = vtrq32(data[1].neon, data[3].neon);
1368 let (q4,q6) = vtrq32(data[4].neon, data[6].neon);
1369 let (q5,q7) = vtrq32(data[5].neon, data[7].neon);
1370
1371 let b1 = vtrnq_s16(q0, q1);
1372 let b2 = vtrnq_s16(q2, q3);
1373 let b3 = vtrnq_s16(q4, q5);
1374 let b4 = vtrnq_s16(q6, q7);
1375
1376 [
1380 i16x8 { neon: vcombine_s16(vget_low_s16(b1.0), vget_low_s16(b3.0)) },
1381 i16x8 { neon: vcombine_s16(vget_low_s16(b1.1), vget_low_s16(b3.1)) },
1382 i16x8 { neon: vcombine_s16(vget_low_s16(b2.0), vget_low_s16(b4.0)) },
1383 i16x8 { neon: vcombine_s16(vget_low_s16(b2.1), vget_low_s16(b4.1)) },
1384 i16x8 { neon: vcombine_s16(vget_high_s16(b1.0), vget_high_s16(b3.0)) },
1385 i16x8 { neon: vcombine_s16(vget_high_s16(b1.1), vget_high_s16(b3.1)) },
1386 i16x8 { neon: vcombine_s16(vget_high_s16(b2.0), vget_high_s16(b4.0)) },
1387 i16x8 { neon: vcombine_s16(vget_high_s16(b2.1), vget_high_s16(b4.1)) },
1388 ]
1389 }
1390 } else if #[cfg(target_feature="simd128")] {
1391 #[inline] fn lo_i16(a : v128, b : v128) -> v128 { i16x8_shuffle::<0, 8, 1, 9, 2, 10, 3, 11>(a,b) }
1392 #[inline] fn hi_i16(a : v128, b : v128) -> v128 { i16x8_shuffle::<4, 12, 5, 13, 6, 14, 7, 15>(a,b) }
1393 #[inline] fn lo_i32(a : v128, b : v128) -> v128 { i32x4_shuffle::<0, 4, 1, 5>(a,b) }
1394 #[inline] fn hi_i32(a : v128, b : v128) -> v128 { i32x4_shuffle::<2, 6, 3, 7>(a,b) }
1395 #[inline] fn lo_i64(a : v128, b : v128) -> v128 { i64x2_shuffle::<0, 2>(a,b) }
1396 #[inline] fn hi_i64(a : v128, b : v128) -> v128 { i64x2_shuffle::<1, 3>(a,b) }
1397
1398 let a1 = lo_i16(data[0].simd, data[1].simd);
1399 let a2 = hi_i16(data[0].simd, data[1].simd);
1400 let a3 = lo_i16(data[2].simd, data[3].simd);
1401 let a4 = hi_i16(data[2].simd, data[3].simd);
1402 let a5 = lo_i16(data[4].simd, data[5].simd);
1403 let a6 = hi_i16(data[4].simd, data[5].simd);
1404 let a7 = lo_i16(data[6].simd, data[7].simd);
1405 let a8 = hi_i16(data[6].simd, data[7].simd);
1406
1407 let b1 = lo_i32(a1, a3);
1408 let b2 = hi_i32(a1, a3);
1409 let b3 = lo_i32(a2, a4);
1410 let b4 = hi_i32(a2, a4);
1411 let b5 = lo_i32(a5, a7);
1412 let b6 = hi_i32(a5, a7);
1413 let b7 = lo_i32(a6, a8);
1414 let b8 = hi_i32(a6, a8);
1415
1416 [
1417 i16x8 { simd: lo_i64(b1, b5) },
1418 i16x8 { simd: hi_i64(b1, b5) },
1419 i16x8 { simd: lo_i64(b2, b6) },
1420 i16x8 { simd: hi_i64(b2, b6) },
1421 i16x8 { simd: lo_i64(b3, b7) },
1422 i16x8 { simd: hi_i64(b3, b7) },
1423 i16x8 { simd: lo_i64(b4, b8) },
1424 i16x8 { simd: hi_i64(b4, b8) } ,
1425 ]
1426
1427 } else {
1428 #[inline(always)]
1429 fn transpose_column(data: &[i16x8; 8], index: usize) -> i16x8 {
1430 i16x8::new([
1431 data[0].as_array()[index],
1432 data[1].as_array()[index],
1433 data[2].as_array()[index],
1434 data[3].as_array()[index],
1435 data[4].as_array()[index],
1436 data[5].as_array()[index],
1437 data[6].as_array()[index],
1438 data[7].as_array()[index],
1439 ])
1440 }
1441
1442 [
1443 transpose_column(&data, 0),
1444 transpose_column(&data, 1),
1445 transpose_column(&data, 2),
1446 transpose_column(&data, 3),
1447 transpose_column(&data, 4),
1448 transpose_column(&data, 5),
1449 transpose_column(&data, 6),
1450 transpose_column(&data, 7),
1451 ]
1452 }
1453 }
1454 }
1455
1456 #[inline]
1457 #[must_use]
1458 pub fn mul_scale_round_n(self, rhs: i16) -> Self {
1466 pick! {
1467 if #[cfg(target_feature="ssse3")] {
1468 Self { sse: mul_i16_scale_round_m128i(self.sse, set_splat_i16_m128i(rhs)) }
1469 } else if #[cfg(target_feature="sse2")] {
1470 let r = set_splat_i16_m128i(rhs);
1472 let hi = mul_i16_keep_high_m128i(self.sse, r);
1473 let lo = mul_i16_keep_low_m128i(self.sse, r);
1474 let mut v1 = unpack_low_i16_m128i(lo, hi);
1475 let mut v2 = unpack_high_i16_m128i(lo, hi);
1476 let a = set_splat_i32_m128i(0x4000);
1477 v1 = shr_imm_i32_m128i::<15>(add_i32_m128i(v1, a));
1478 v2 = shr_imm_i32_m128i::<15>(add_i32_m128i(v2, a));
1479 let s = pack_i32_to_i16_m128i(v1, v2);
1480 Self { sse: s }
1481 } else if #[cfg(target_feature="simd128")] {
1482 Self { simd: i16x8_q15mulr_sat(self.simd, i16x8_splat(rhs)) }
1483 } else if #[cfg(all(target_feature="neon",target_arch="aarch64"))]{
1484 unsafe { Self { neon: vqrdmulhq_n_s16(self.neon, rhs) } }
1485 } else {
1486 Self { arr: [
1488 ((i32::from(self.arr[0]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1489 ((i32::from(self.arr[1]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1490 ((i32::from(self.arr[2]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1491 ((i32::from(self.arr[3]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1492 ((i32::from(self.arr[4]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1493 ((i32::from(self.arr[5]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1494 ((i32::from(self.arr[6]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1495 ((i32::from(self.arr[7]) * i32::from(rhs) + 0x4000) >> 15) as i16,
1496 ]}
1497 }
1498 }
1499 }
1500
1501 #[inline]
1502 pub fn to_array(self) -> [i16; 8] {
1503 cast(self)
1504 }
1505
1506 #[inline]
1507 pub fn as_array(&self) -> &[i16; 8] {
1508 cast_ref(self)
1509 }
1510
1511 #[inline]
1512 pub fn as_mut_array(&mut self) -> &mut [i16; 8] {
1513 cast_mut(self)
1514 }
1515}