1use super::*;
2
3simd_type!({
5 #[allow(missing_docs)]
7 pub struct V2 {
8 pub sse: f!("sse"),
9 pub sse2: f!("sse2"),
10 pub fxsr: f!("fxsr"),
11 pub sse3: f!("sse3"),
12 pub ssse3: f!("ssse3"),
13 pub sse4_1: f!("sse4.1"),
14 pub sse4_2: f!("sse4.2"),
15 pub popcnt: f!("popcnt"),
16 }
17});
18
19impl Seal for V2 {}
20
21impl Deref for V2 {
22 type Target = V1;
23
24 #[inline(always)]
25 fn deref(&self) -> &Self::Target {
26 V1 {
27 sse: self.sse,
28 sse2: self.sse2,
29 fxsr: self.fxsr,
30 }
31 .to_ref()
32 }
33}
34
35impl V2 {
36 binop_128!(ssse3: sign, r#"Applies the sign of each element of `sign` to the corresponding lane in `a`.
37- If `sign` is zero, the corresponding element is zeroed.
38- If `sign` is positive, the corresponding element is returned as is.
39- If `sign` is negative, the corresponding element is negated."#, apply_sign, i8 x 16, i16 x 8, i32 x 4);
40
41 unop_128!(sse4_1: ceil, "Returns `ceil(a)` for each lane of `a`, rounding towards positive infinity.", f32 x 4, f64 x 2);
42
43 binop_128_nosign!(sse4_1: cmpeq, "Compares the elements in each lane of `a` and `b` for equality.", cmp_eq, m64 x 2 => m64, u64 x 2 => m64, i64 x 2 => m64);
44
45 binop_128!(sse4_2: cmpgt, "Compares the elements in each lane of `a` and `b` for equality.", cmp_gt, i64 x 2 => m64);
46
47 unop_128!(sse4_1: floor, "Rounds the elements of each lane of `a` to the nearest integer towards negative infinity.", f32 x 4, f64 x 2);
48
49 binop_128_nosign!(sse3: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, f32 x 4, f64 x 2);
50
51 binop_128_nosign!(ssse3: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
52
53 binop_128_nosign!(sse3: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, f32 x 4, f64 x 2);
54
55 binop_128_nosign!(ssse3: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
56
57 binop_128!(sse4_1: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", i8 x 16, u16 x 8, u32 x 4, i32 x 4);
58
59 binop_128!(sse4_1: min, "Computes `max(a, b)`. for each lane in `a` and `b`.", i8 x 16, u16 x 8, u32 x 4, i32 x 4);
60
61 binop_128_nosign!(sse4_1: mullo, "Computes `a * b` for each lane in `a` and `b`, with wrapping overflow.", wrapping_mul, u32 x 4, i32 x 4);
62
63 binop_128!(sse3: addsub, "Alternatively subtracts and adds the elements of each lane of `a` and `b`.", subadd, f32 x 4, f64 x 2);
64
65 unop_128!(ssse3: abs, "Computes the unsigned absolute value of the elements of each lane of `a`.", unsigned_abs, i8 x 16, i16 x 8, i32 x 4);
66
67 #[inline(always)]
69 pub fn abs_f32x4(self, a: f32x4) -> f32x4 {
70 self.and_f32x4(a, cast!(self.splat_u32x4((1 << 31) - 1)))
71 }
72
73 #[inline(always)]
75 pub fn abs_f64x2(self, a: f64x2) -> f64x2 {
76 self.and_f64x2(a, cast!(self.splat_u64x2((1 << 63) - 1)))
77 }
78
79 #[inline(always)]
81 pub fn approx_reciprocal_f32x4(self, a: f32x4) -> f32x4 {
82 cast!(self.sse._mm_rcp_ps(cast!(a)))
83 }
84
85 #[inline(always)]
87 pub fn approx_reciprocal_sqrt_f32x4(self, a: f32x4) -> f32x4 {
88 cast!(self.sse._mm_rsqrt_ps(cast!(a)))
89 }
90
91 #[inline(always)]
93 pub fn cmp_ge_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
94 self.not_m64x2(self.cmp_lt_i64x2(a, b))
95 }
96
97 #[inline(always)]
99 pub fn cmp_ge_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
100 self.not_m64x2(self.cmp_lt_u64x2(a, b))
101 }
102
103 #[inline(always)]
105 pub fn cmp_gt_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
106 let k = self.splat_u64x2(0x8000000000000000);
107 self.cmp_gt_i64x2(cast!(self.xor_u64x2(a, k)), cast!(self.xor_u64x2(b, k)))
108 }
109
110 #[inline(always)]
112 pub fn cmp_le_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
113 self.not_m64x2(self.cmp_gt_i64x2(a, b))
114 }
115
116 #[inline(always)]
118 pub fn cmp_le_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
119 self.not_m64x2(self.cmp_gt_u64x2(a, b))
120 }
121
122 #[inline(always)]
124 pub fn cmp_lt_i64x2(self, a: i64x2, b: i64x2) -> m64x2 {
125 cast!(self.sse4_2._mm_cmpgt_epi64(cast!(b), cast!(a)))
126 }
127
128 #[inline(always)]
130 pub fn cmp_lt_u64x2(self, a: u64x2, b: u64x2) -> m64x2 {
131 let k = self.splat_u64x2(0x8000000000000000);
132 self.cmp_lt_i64x2(cast!(self.xor_u64x2(a, k)), cast!(self.xor_u64x2(b, k)))
133 }
134
135 #[inline(always)]
137 pub fn convert_i16x8_to_i32x4(self, a: i16x8) -> i32x4 {
138 cast!(self.sse4_1._mm_cvtepi16_epi32(cast!(a)))
139 }
140
141 #[inline(always)]
143 pub fn convert_i16x8_to_i64x2(self, a: i16x8) -> i64x2 {
144 cast!(self.sse4_1._mm_cvtepi16_epi64(cast!(a)))
145 }
146
147 #[inline(always)]
149 pub fn convert_i16x8_to_u32x4(self, a: i16x8) -> u32x4 {
150 cast!(self.sse4_1._mm_cvtepi16_epi32(cast!(a)))
151 }
152
153 #[inline(always)]
155 pub fn convert_i16x8_to_u64x2(self, a: i16x8) -> u64x2 {
156 cast!(self.sse4_1._mm_cvtepi16_epi64(cast!(a)))
157 }
158
159 #[inline(always)]
161 pub fn convert_i32x4_to_i64x2(self, a: i32x4) -> i64x2 {
162 cast!(self.sse4_1._mm_cvtepi32_epi64(cast!(a)))
163 }
164
165 #[inline(always)]
167 pub fn convert_i32x4_to_u64x2(self, a: i32x4) -> u64x2 {
168 cast!(self.sse4_1._mm_cvtepi32_epi64(cast!(a)))
169 }
170
171 #[inline(always)]
173 pub fn convert_i8x16_to_i16x8(self, a: i8x16) -> i16x8 {
174 cast!(self.sse4_1._mm_cvtepi8_epi16(cast!(a)))
175 }
176
177 #[inline(always)]
179 pub fn convert_i8x16_to_i32x4(self, a: i8x16) -> i32x4 {
180 cast!(self.sse4_1._mm_cvtepi8_epi32(cast!(a)))
181 }
182
183 #[inline(always)]
185 pub fn convert_i8x16_to_i64x2(self, a: i8x16) -> i64x2 {
186 cast!(self.sse4_1._mm_cvtepi8_epi64(cast!(a)))
187 }
188
189 #[inline(always)]
191 pub fn convert_i8x16_to_u16x8(self, a: i8x16) -> u16x8 {
192 cast!(self.sse4_1._mm_cvtepi8_epi16(cast!(a)))
193 }
194
195 #[inline(always)]
197 pub fn convert_i8x16_to_u32x4(self, a: i8x16) -> u32x4 {
198 cast!(self.sse4_1._mm_cvtepi8_epi32(cast!(a)))
199 }
200
201 #[inline(always)]
203 pub fn convert_i8x16_to_u64x2(self, a: i8x16) -> u64x2 {
204 cast!(self.sse4_1._mm_cvtepi8_epi64(cast!(a)))
205 }
206
207 #[inline(always)]
209 pub fn convert_u16x8_to_i32x4(self, a: u16x8) -> i32x4 {
210 cast!(self.sse4_1._mm_cvtepu16_epi32(cast!(a)))
211 }
212
213 #[inline(always)]
215 pub fn convert_u16x8_to_i64x2(self, a: u16x8) -> i64x2 {
216 cast!(self.sse4_1._mm_cvtepu16_epi64(cast!(a)))
217 }
218
219 #[inline(always)]
221 pub fn convert_u16x8_to_u32x4(self, a: u16x8) -> u32x4 {
222 cast!(self.sse4_1._mm_cvtepu16_epi32(cast!(a)))
223 }
224
225 #[inline(always)]
227 pub fn convert_u16x8_to_u64x2(self, a: u16x8) -> u64x2 {
228 cast!(self.sse4_1._mm_cvtepu16_epi64(cast!(a)))
229 }
230
231 #[inline(always)]
233 pub fn convert_u32x4_to_i64x2(self, a: u32x4) -> i64x2 {
234 cast!(self.sse4_1._mm_cvtepu32_epi64(cast!(a)))
235 }
236
237 #[inline(always)]
239 pub fn convert_u32x4_to_u64x2(self, a: u32x4) -> u64x2 {
240 cast!(self.sse4_1._mm_cvtepu32_epi64(cast!(a)))
241 }
242
243 #[inline(always)]
245 pub fn convert_u8x16_to_i16x8(self, a: u8x16) -> i16x8 {
246 cast!(self.sse4_1._mm_cvtepu8_epi16(cast!(a)))
247 }
248
249 #[inline(always)]
251 pub fn convert_u8x16_to_i32x4(self, a: u8x16) -> i32x4 {
252 cast!(self.sse4_1._mm_cvtepu8_epi32(cast!(a)))
253 }
254
255 #[inline(always)]
257 pub fn convert_u8x16_to_i64x2(self, a: u8x16) -> i64x2 {
258 cast!(self.sse4_1._mm_cvtepu8_epi64(cast!(a)))
259 }
260
261 #[inline(always)]
263 pub fn convert_u8x16_to_i8x16(self, a: u8x16) -> i8x16 {
264 cast!(a)
265 }
266
267 #[inline(always)]
269 pub fn convert_u8x16_to_u16x8(self, a: u8x16) -> u16x8 {
270 cast!(self.sse4_1._mm_cvtepu8_epi16(cast!(a)))
271 }
272
273 #[inline(always)]
275 pub fn convert_u8x16_to_u32x4(self, a: u8x16) -> u32x4 {
276 cast!(self.sse4_1._mm_cvtepu8_epi32(cast!(a)))
277 }
278
279 #[inline(always)]
281 pub fn convert_u8x16_to_u64x2(self, a: u8x16) -> u64x2 {
282 cast!(self.sse4_1._mm_cvtepu8_epi64(cast!(a)))
283 }
284
285 #[inline(always)]
289 pub fn horizontal_saturating_add_pack_i16x8(self, a: i16x8, b: i16x8) -> i16x8 {
290 cast!(self.ssse3._mm_hadds_epi16(cast!(a), cast!(b)))
291 }
292
293 #[inline(always)]
297 pub fn horizontal_saturating_sub_pack_i16x8(self, a: i16x8, b: i16x8) -> i16x8 {
298 cast!(self.ssse3._mm_hsubs_epi16(cast!(a), cast!(b)))
299 }
300
301 #[inline(always)]
305 pub fn multiply_saturating_add_adjacent_i8x16(self, a: i8x16, b: i8x16) -> i16x8 {
306 cast!(self.ssse3._mm_maddubs_epi16(cast!(a), cast!(b)))
307 }
308
309 #[inline(always)]
313 pub fn multisum_of_absolute_differences_u8x16<const OFFSETS: i32>(
314 self,
315 a: u8x16,
316 b: u8x16,
317 ) -> u16x8 {
318 cast!(self.sse4_1._mm_mpsadbw_epu8::<OFFSETS>(cast!(a), cast!(b)))
319 }
320
321 #[inline(always)]
325 pub fn pack_with_unsigned_saturation_i32x4(self, a: i32x4, b: i32x4) -> u16x8 {
326 cast!(self.sse4_1._mm_packus_epi32(cast!(a), cast!(b)))
327 }
328
329 #[inline(always)]
332 pub fn round_f32x4(self, a: f32x4) -> f32x4 {
333 const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
334 cast!(self.sse4_1._mm_round_ps::<ROUNDING>(cast!(a)))
335 }
336
337 #[inline(always)]
340 pub fn round_f64x2(self, a: f64x2) -> f64x2 {
341 const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
342 cast!(self.sse4_1._mm_round_pd::<ROUNDING>(cast!(a)))
343 }
344
345 #[inline(always)]
348 pub fn select_const_f32x4<const MASK4: i32>(self, if_true: f32x4, if_false: f32x4) -> f32x4 {
349 cast!(self.select_const_u32x4::<MASK4>(cast!(if_true), cast!(if_false)))
350 }
351
352 #[inline(always)]
355 pub fn select_const_f64x2<const MASK2: i32>(self, if_true: f64x2, if_false: f64x2) -> f64x2 {
356 cast!(self.select_const_u64x2::<MASK2>(cast!(if_true), cast!(if_false)))
357 }
358
359 #[inline(always)]
362 pub fn select_const_i32x4<const MASK4: i32>(self, if_true: i32x4, if_false: i32x4) -> i32x4 {
363 cast!(self.select_const_u32x4::<MASK4>(cast!(if_true), cast!(if_false)))
364 }
365
366 #[inline(always)]
369 pub fn select_const_i64x2<const MASK2: i32>(self, if_true: i64x2, if_false: i64x2) -> i64x2 {
370 cast!(self.select_const_u64x2::<MASK2>(cast!(if_true), cast!(if_false)))
371 }
372
373 #[inline(always)]
376 pub fn select_const_u32x4<const MASK4: i32>(self, if_true: u32x4, if_false: u32x4) -> u32x4 {
377 cast!(
378 self.sse4_1
379 ._mm_blend_ps::<MASK4>(cast!(if_false), cast!(if_true)),
380 )
381 }
382
383 #[inline(always)]
386 pub fn select_const_u64x2<const MASK2: i32>(self, if_true: u64x2, if_false: u64x2) -> u64x2 {
387 cast!(
388 self.sse4_1
389 ._mm_blend_pd::<MASK2>(cast!(if_false), cast!(if_true)),
390 )
391 }
392
393 #[inline(always)]
396 pub fn select_f32x4(self, mask: m32x4, if_true: f32x4, if_false: f32x4) -> f32x4 {
397 cast!(
398 self.sse4_1
399 ._mm_blendv_ps(cast!(if_false), cast!(if_true), cast!(mask)),
400 )
401 }
402
403 #[inline(always)]
406 pub fn select_f64x2(self, mask: m64x2, if_true: f64x2, if_false: f64x2) -> f64x2 {
407 cast!(
408 self.sse4_1
409 ._mm_blendv_pd(cast!(if_false), cast!(if_true), cast!(mask)),
410 )
411 }
412
413 #[inline(always)]
416 pub fn select_i16x8(self, mask: m16x8, if_true: i16x8, if_false: i16x8) -> i16x8 {
417 cast!(self.select_u16x8(mask, cast!(if_true), cast!(if_false)))
418 }
419
420 #[inline(always)]
423 pub fn select_i32x4(self, mask: m32x4, if_true: i32x4, if_false: i32x4) -> i32x4 {
424 cast!(self.select_u32x4(mask, cast!(if_true), cast!(if_false)))
425 }
426
427 #[inline(always)]
430 pub fn select_i64x2(self, mask: m64x2, if_true: i64x2, if_false: i64x2) -> i64x2 {
431 cast!(self.select_u64x2(mask, cast!(if_true), cast!(if_false)))
432 }
433
434 #[inline(always)]
437 pub fn select_i8x16(self, mask: m8x16, if_true: i8x16, if_false: i8x16) -> i8x16 {
438 cast!(self.select_u8x16(mask, cast!(if_true), cast!(if_false)))
439 }
440
441 #[inline(always)]
444 pub fn select_u16x8(self, mask: m16x8, if_true: u16x8, if_false: u16x8) -> u16x8 {
445 cast!(
446 self.sse4_1
447 ._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
448 )
449 }
450
451 #[inline(always)]
454 pub fn select_u32x4(self, mask: m32x4, if_true: u32x4, if_false: u32x4) -> u32x4 {
455 cast!(
456 self.sse4_1
457 ._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
458 )
459 }
460
461 #[inline(always)]
464 pub fn select_u64x2(self, mask: m64x2, if_true: u64x2, if_false: u64x2) -> u64x2 {
465 cast!(
466 self.sse4_1
467 ._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
468 )
469 }
470
471 #[inline(always)]
474 pub fn select_u8x16(self, mask: m8x16, if_true: u8x16, if_false: u8x16) -> u8x16 {
475 cast!(
476 self.sse4_1
477 ._mm_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
478 )
479 }
480
481 #[inline(always)]
483 pub fn truncate_f32x4(self, a: f32x4) -> f32x4 {
484 const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
485 cast!(self.sse4_1._mm_round_ps::<ROUNDING>(cast!(a)))
486 }
487
488 #[inline(always)]
490 pub fn truncate_f64x2(self, a: f64x2) -> f64x2 {
491 const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
492 cast!(self.sse4_1._mm_round_pd::<ROUNDING>(cast!(a)))
493 }
494
495 #[inline(always)]
498 pub fn widening_mul_i32x4(self, a: i32x4, b: i32x4) -> (u32x4, i32x4) {
499 let a = cast!(a);
500 let b = cast!(b);
501 let sse = self.sse2;
502
503 let ab_evens = self.sse4_1._mm_mul_epi32(a, b);
505 let ab_odds = self
507 .sse4_1
508 ._mm_mul_epi32(sse._mm_srli_epi64::<32>(a), sse._mm_srli_epi64::<32>(b));
509
510 let ab_lo = self.sse4_1._mm_blend_ps::<0b1010>(
511 cast!(ab_evens),
513 cast!(sse._mm_slli_epi64::<32>(ab_odds)),
515 );
516 let ab_hi = self.sse4_1._mm_blend_ps::<0b1010>(
517 cast!(sse._mm_srli_epi64::<32>(ab_evens)),
519 cast!(ab_odds),
521 );
522
523 (cast!(ab_lo), cast!(ab_hi))
524 }
525
526 #[inline(always)]
529 pub fn widening_mul_u32x4(self, a: u32x4, b: u32x4) -> (u32x4, u32x4) {
530 let a = cast!(a);
531 let b = cast!(b);
532 let sse = self.sse2;
533
534 let ab_evens = sse._mm_mul_epu32(a, b);
536 let ab_odds = sse._mm_mul_epu32(sse._mm_srli_epi64::<32>(a), sse._mm_srli_epi64::<32>(b));
538
539 let ab_lo = self.sse4_1._mm_blend_ps::<0b1010>(
540 cast!(ab_evens),
542 cast!(sse._mm_slli_epi64::<32>(ab_odds)),
544 );
545 let ab_hi = self.sse4_1._mm_blend_ps::<0b1010>(
546 cast!(sse._mm_srli_epi64::<32>(ab_evens)),
548 cast!(ab_odds),
550 );
551
552 (cast!(ab_lo), cast!(ab_hi))
553 }
554}
555
556macro_rules! impl_simd_binop {
557 ($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
558 paste! {
559 #[inline(always)]
560 fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
561 self.[<$op _ $ty x $factor>](a, b)
562 }
563 }
564 };
565 ($func: ident, $op: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
566 $(impl_simd_binop!($func, $op, $ty, $out, $factor);)*
567 };
568 ($func: ident, $op: ident, $($ty: ident x $factor: literal),*) => {
569 $(impl_simd_binop!($func, $op, $ty, $ty, $factor);)*
570 };
571 ($func: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
572 $(impl_simd_binop!($func, $func, $ty, $out, $factor);)*
573 };
574 ($func: ident, $($ty: ident x $factor: literal),*) => {
575 $(impl_simd_binop!($func, $func, $ty, $ty, $factor);)*
576 };
577}
578
579macro_rules! impl_simd_unop {
580 ($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
581 paste! {
582 #[inline(always)]
583 fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$out s>] {
584 self.[<$op _ $ty x $factor>](a)
585 }
586 }
587 };
588 ($func: ident, $($ty: ident x $factor: literal),*) => {
589 $(impl_simd_unop!($func, $func, $ty, $ty, $factor);)*
590 };
591}
592
593macro_rules! impl_scalar_binop {
594 ($func: ident, $ty: ident, $out: ty, impl) => {
595 paste! {
596 #[inline(always)]
597 fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
598 Scalar128b.[<$func _ $ty s>](a, b)
599 }
600 }
601 };
602 ($func: ident, $($ty: ident => $out: ty),*) => {
603 $(impl_scalar_binop!($func, $ty, $out, impl);)*
604 };
605 ($func: ident, $($ty: ident),*) => {
606 $(impl_scalar_binop!($func, $ty, $ty, impl);)*
607 };
608}
609
610macro_rules! splat {
611 ($ty: ty, $factor: literal) => {
612 paste! {
613 #[inline(always)]
614 fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>] {
615 self.[<splat_ $ty x $factor>](value)
616 }
617 }
618 };
619 ($($ty: ident x $factor: literal),*) => {
620 $(splat!($ty, $factor);)*
621 };
622}
623
624impl Simd for V2 {
625 type c32s = f32x4;
626 type c64s = f64x2;
627 type f32s = f32x4;
628 type f64s = f64x2;
629 type i16s = i16x8;
630 type i32s = i32x4;
631 type i64s = i64x2;
632 type i8s = i8x16;
633 type m16s = m16x8;
634 type m32s = m32x4;
635 type m64s = m64x2;
636 type m8s = m8x16;
637 type u16s = u16x8;
638 type u32s = u32x4;
639 type u64s = u64x2;
640 type u8s = u8x16;
641
642 const REGISTER_COUNT: usize = 16;
643
644 impl_simd_binop!(add, f32 x 4, f64 x 2);
645
646 impl_simd_binop!(add, wrapping_add, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2);
647
648 impl_simd_binop!(sub, f32 x 4, f64 x 2);
649
650 impl_simd_binop!(sub, wrapping_sub, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2);
651
652 impl_simd_binop!(mul, f32 x 4, f64 x 2);
653
654 impl_simd_binop!(mul, wrapping_mul, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
655
656 impl_scalar_binop!(mul, u64, i64, c32, c64);
657
658 impl_simd_binop!(and, m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2, f32 x 4, f64 x 2);
659
660 impl_simd_binop!(or, m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2, f32 x 4, f64 x 2);
661
662 impl_simd_binop!(xor, m8 x 16, u8 x 16, i8 x 16, m16 x 8, u16 x 8, i16 x 8, m32 x 4, u32 x 4, i32 x 4, m64 x 2, u64 x 2, i64 x 2, f32 x 4, f64 x 2);
663
664 impl_simd_binop!(div, f32 x 4, f64 x 2);
665
666 impl_simd_binop!(equal, cmp_eq, u8 x 16 => m8, u16 x 8 => m16, u32 x 4 => m32, u64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
667
668 impl_simd_binop!(greater_than, cmp_gt, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
669
670 impl_simd_binop!(greater_than_or_equal, cmp_ge, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
671
672 impl_simd_binop!(less_than, cmp_lt, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
673
674 impl_simd_binop!(less_than_or_equal, cmp_le, u8 x 16 => m8, i8 x 16 => m8, u16 x 8 => m16, i16 x 8 => m16, u32 x 4 => m32, i32 x 4 => m32, u64 x 2 => m64, i64 x 2 => m64, f32 x 4 => m32, f64 x 2 => m64);
675
676 impl_scalar_binop!(conj_mul, c32, c64);
677
678 splat!(u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, u64 x 2, i64 x 2, f32 x 4, f64 x 2);
679
680 impl_simd_binop!(max, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, f32 x 4, f64 x 2);
681
682 impl_scalar_binop!(max, u64, i64);
683
684 impl_simd_binop!(min, u8 x 16, i8 x 16, u16 x 8, i16 x 8, u32 x 4, i32 x 4, f32 x 4, f64 x 2);
685
686 impl_scalar_binop!(min, u64, i64);
687
688 impl_simd_unop!(not, m8 x 16, u8 x 16, m16 x 8, u16 x 8, m32 x 4, u32 x 4, m64 x 2, u64 x 2);
689
690 fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
691 let sqr = self.mul_f32s(a, a);
692 let sqr_rev = self
693 .sse
694 ._mm_shuffle_ps::<0b10_11_00_01>(cast!(sqr), cast!(sqr));
695 self.add_f32s(sqr, cast!(sqr_rev))
696 }
697
698 fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
699 let sqr = self.mul_f64s(a, a);
700 let sqr_rev = self.sse2._mm_shuffle_pd::<0b0101>(cast!(sqr), cast!(sqr));
701 self.add_f64s(sqr, cast!(sqr_rev))
702 }
703
704 fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
705 let max = self.abs_f32s(a);
706 let max_rev = self.sse._mm_shuffle_ps::<0b10_11_00_01>(cast!(a), cast!(a));
707 self.max_f32s(max, cast!(max_rev))
708 }
709
710 fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
711 let max = self.abs_f64s(a);
712 let max_rev = self.sse2._mm_shuffle_pd::<0b0101>(cast!(max), cast!(max));
713 self.max_f64s(max, cast!(max_rev))
714 }
715
716 #[inline(always)]
717 fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
718 self.add_f32s(a, b)
719 }
720
721 #[inline(always)]
722 fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
723 self.add_f64s(a, b)
724 }
725
726 #[inline(always)]
727 fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s {
728 self.equal_f32s(a, b)
729 }
730
731 #[inline(always)]
732 fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s {
733 self.equal_f64s(a, b)
734 }
735
736 #[inline(always)]
737 fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
738 self.xor_f32s(a, self.splat_c32s(c32 { re: 0.0, im: -0.0 }))
739 }
740
741 #[inline(always)]
742 fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
743 self.xor_f64s(a, self.splat_c64s(c64 { re: 0.0, im: -0.0 }))
744 }
745
746 #[inline(always)]
747 fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
748 Scalar128b.conj_mul_add_c32s(a, b, c)
749 }
750
751 #[inline(always)]
752 fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
753 Scalar128b.conj_mul_add_c64s(a, b, c)
754 }
755
756 #[inline(always)]
760 unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
761 cast!(self.mask_load_ptr_u32s(mask, ptr as _))
762 }
763
764 #[inline(always)]
768 unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
769 cast!(self.mask_load_ptr_u64s(mask, ptr as _))
770 }
771
772 #[inline(always)]
776 unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
777 Scalar128b.mask_load_ptr_u8s(mask, ptr)
778 }
779
780 #[inline(always)]
784 unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
785 Scalar128b.mask_load_ptr_u16s(mask, ptr)
786 }
787
788 #[inline(always)]
792 unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
793 Scalar128b.mask_load_ptr_u32s(mask, ptr)
794 }
795
796 #[inline(always)]
800 unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
801 cast!(self.mask_load_ptr_u32s(
802 MemMask {
803 mask: cast!(mask.mask),
804 #[cfg(target_arch = "x86_64")]
805 load: mask.load,
806 #[cfg(target_arch = "x86_64")]
807 store: mask.store
808 },
809 ptr as _
810 ))
811 }
812
813 #[inline(always)]
817 unsafe fn mask_store_ptr_c32s(
818 self,
819 mask: MemMask<Self::m32s>,
820 ptr: *mut c32,
821 values: Self::c32s,
822 ) {
823 self.mask_store_ptr_u32s(mask, ptr as _, cast!(values))
824 }
825
826 #[inline(always)]
830 unsafe fn mask_store_ptr_c64s(
831 self,
832 mask: MemMask<Self::m64s>,
833 ptr: *mut c64,
834 values: Self::c64s,
835 ) {
836 self.mask_store_ptr_u64s(mask, ptr as _, cast!(values))
837 }
838
839 #[inline(always)]
843 unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
844 Scalar128b.mask_store_ptr_u8s(mask, ptr, values);
845 }
846
847 #[inline(always)]
851 unsafe fn mask_store_ptr_u16s(
852 self,
853 mask: MemMask<Self::m16s>,
854 ptr: *mut u16,
855 values: Self::u16s,
856 ) {
857 Scalar128b.mask_store_ptr_u16s(mask, ptr, values);
858 }
859
860 #[inline(always)]
864 unsafe fn mask_store_ptr_u32s(
865 self,
866 mask: MemMask<Self::m32s>,
867 ptr: *mut u32,
868 values: Self::u32s,
869 ) {
870 Scalar128b.mask_store_ptr_u32s(mask, ptr, values);
871 }
872
873 #[inline(always)]
877 unsafe fn mask_store_ptr_u64s(
878 self,
879 mask: MemMask<Self::m64s>,
880 ptr: *mut u64,
881 values: Self::u64s,
882 ) {
883 self.mask_store_ptr_u32s(
884 MemMask {
885 mask: cast!(mask.mask),
886 #[cfg(target_arch = "x86_64")]
887 load: mask.load,
888 #[cfg(target_arch = "x86_64")]
889 store: mask.store,
890 },
891 ptr as _,
892 cast!(values),
893 )
894 }
895
896 #[inline(always)]
897 fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
898 Scalar128b.mul_add_c32s(a, b, c)
899 }
900
901 #[inline(always)]
902 fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
903 Scalar128b.mul_add_c64s(a, b, c)
904 }
905
906 #[inline(always)]
907 fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
908 self.mul_add_f32s(a, b, c)
909 }
910
911 #[inline(always)]
912 fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
913 self.mul_add_f64s(a, b, c)
914 }
915
916 #[inline(always)]
917 fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
918 Scalar128b.mul_add_f32s(a, b, c)
919 }
920
921 #[inline(always)]
922 fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
923 Scalar128b.mul_add_f64s(a, b, c)
924 }
925
926 #[inline(always)]
927 fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
928 self.negate_mul_add_f32s(a, b, c)
929 }
930
931 #[inline(always)]
932 fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
933 self.negate_mul_add_f64s(a, b, c)
934 }
935
936 #[inline(always)]
937 fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
938 Scalar128b.negate_mul_add_f32s(a, b, c)
939 }
940
941 #[inline(always)]
942 fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
943 Scalar128b.negate_mul_add_f64s(a, b, c)
944 }
945
946 #[inline(always)]
947 fn neg_c32s(self, a: Self::c32s) -> Self::c32s {
948 self.xor_f32s(a, self.splat_f32s(-0.0))
949 }
950
951 #[inline(always)]
952 fn neg_c64s(self, a: Self::c64s) -> Self::c64s {
953 self.xor_f64s(a, self.splat_f64s(-0.0))
954 }
955
956 #[inline(always)]
957 fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
958 self.reduce_max_c32x2(a)
959 }
960
961 #[inline(always)]
962 fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
963 self.reduce_max_c64x1(a)
964 }
965
966 #[inline(always)]
967 fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
968 self.reduce_max_f32x4(a)
969 }
970
971 #[inline(always)]
972 fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
973 self.reduce_max_f64x2(a)
974 }
975
976 #[inline(always)]
977 fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
978 self.reduce_min_c32x2(a)
979 }
980
981 #[inline(always)]
982 fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
983 self.reduce_min_c64x1(a)
984 }
985
986 #[inline(always)]
987 fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
988 self.reduce_min_f32x4(a)
989 }
990
991 #[inline(always)]
992 fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
993 self.reduce_min_f64x2(a)
994 }
995
996 #[inline(always)]
997 fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
998 self.reduce_product_f32x4(a)
999 }
1000
1001 #[inline(always)]
1002 fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
1003 self.reduce_product_f64x2(a)
1004 }
1005
1006 #[inline(always)]
1007 fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
1008 self.reduce_sum_c32x2(a)
1009 }
1010
1011 #[inline(always)]
1012 fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
1013 self.reduce_sum_c64x1(a)
1014 }
1015
1016 #[inline(always)]
1017 fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
1018 self.reduce_sum_f32x4(a)
1019 }
1020
1021 #[inline(always)]
1022 fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
1023 self.reduce_sum_f64x2(a)
1024 }
1025
1026 #[inline(always)]
1027 fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
1028 Scalar128b.rotate_right_c32s(a, amount)
1029 }
1030
1031 #[inline(always)]
1032 fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
1033 Scalar128b.rotate_right_c64s(a, amount)
1034 }
1035
1036 #[inline(always)]
1037 fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
1038 Scalar128b.rotate_right_u32s(a, amount)
1039 }
1040
1041 #[inline(always)]
1042 fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
1043 Scalar128b.rotate_right_u64s(a, amount)
1044 }
1045
1046 #[inline(always)]
1047 fn select_u32s(
1048 self,
1049 mask: Self::m32s,
1050 if_true: Self::u32s,
1051 if_false: Self::u32s,
1052 ) -> Self::u32s {
1053 let mask: __m128 = cast!(mask);
1054 let if_true: __m128 = cast!(if_true);
1055 let if_false: __m128 = cast!(if_false);
1056
1057 cast!(self.sse4_1._mm_blendv_ps(if_false, if_true, mask))
1058 }
1059
1060 #[inline(always)]
1061 fn select_u64s(
1062 self,
1063 mask: Self::m64s,
1064 if_true: Self::u64s,
1065 if_false: Self::u64s,
1066 ) -> Self::u64s {
1067 let mask: __m128d = cast!(mask);
1068 let if_true: __m128d = cast!(if_true);
1069 let if_false: __m128d = cast!(if_false);
1070
1071 cast!(self.sse4_1._mm_blendv_pd(if_false, if_true, mask))
1072 }
1073
1074 #[inline(always)]
1075 fn splat_c32s(self, value: c32) -> Self::c32s {
1076 cast!(self.splat_f64s(cast!(value)))
1077 }
1078
1079 #[inline(always)]
1080 fn splat_c64s(self, value: c64) -> Self::c64s {
1081 Scalar128b.splat_c64s(value)
1082 }
1083
1084 #[inline(always)]
1085 fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1086 self.sub_f32s(a, b)
1087 }
1088
1089 #[inline(always)]
1090 fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1091 self.sub_f64s(a, b)
1092 }
1093
1094 #[inline(always)]
1095 fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
1096 Scalar128b.swap_re_im_c32s(a)
1097 }
1098
1099 #[inline(always)]
1100 fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
1101 Scalar128b.swap_re_im_c64s(a)
1102 }
1103
1104 #[inline(always)]
1105 fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
1106 struct Impl<Op> {
1107 this: V2,
1108 op: Op,
1109 }
1110 impl<Op: WithSimd> crate::NullaryFnOnce for Impl<Op> {
1111 type Output = Op::Output;
1112
1113 #[inline(always)]
1114 fn call(self) -> Self::Output {
1115 self.op.with_simd(self.this)
1116 }
1117 }
1118 self.vectorize(Impl { this: self, op })
1119 }
1120
1121 #[inline(always)]
1122 fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
1123 self.widening_mul_u32x4(a, b)
1124 }
1125
1126 #[inline(always)]
1127 fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1128 Scalar128b.wrapping_dyn_shl_u32s(a, amount)
1129 }
1130
1131 #[inline(always)]
1132 fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1133 Scalar128b.wrapping_dyn_shr_u32s(a, amount)
1134 }
1135
1136 #[inline(always)]
1137 fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
1138 self.sqrt_f32x4(a)
1139 }
1140
1141 #[inline(always)]
1142 fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
1143 self.sqrt_f64x2(a)
1144 }
1145}