1use super::*;
2
3simd_type!({
5 #[allow(missing_docs)]
12 pub struct V3 {
13 pub sse: f!("sse"),
14 pub sse2: f!("sse2"),
15 pub fxsr: f!("fxsr"),
16 pub sse3: f!("sse3"),
17 pub ssse3: f!("ssse3"),
18 pub sse4_1: f!("sse4.1"),
19 pub sse4_2: f!("sse4.2"),
20 pub popcnt: f!("popcnt"),
21 pub avx: f!("avx"),
22 pub avx2: f!("avx2"),
23 pub bmi1: f!("bmi1"),
24 pub bmi2: f!("bmi2"),
25 pub fma: f!("fma"),
26 pub lzcnt: f!("lzcnt"),
27 }
28});
29
30#[inline(always)]
32fn avx2_pshufb(simd: V3, bytes: __m256i, idxs: __m256i) -> __m256i {
33 let mid = simd.avx._mm256_set1_epi8(16i8);
34 let high = simd.avx._mm256_set1_epi8(32i8);
35 let hihi = simd.avx2._mm256_permute2x128_si256::<0x11>(bytes, bytes);
42 let hi_shuf = simd.avx2._mm256_shuffle_epi8(
43 hihi, idxs, );
46 let compose = simd.avx2._mm256_blendv_epi8(
48 simd.avx._mm256_set1_epi8(0),
49 hi_shuf,
50 simd.avx2._mm256_cmpgt_epi8(high, idxs),
51 );
52 let lolo = simd.avx2._mm256_permute2x128_si256::<0x00>(bytes, bytes);
53 let lo_shuf = simd.avx2._mm256_shuffle_epi8(lolo, idxs);
54 simd.avx2
56 ._mm256_blendv_epi8(compose, lo_shuf, simd.avx2._mm256_cmpgt_epi8(mid, idxs))
57}
58
59static AVX2_ROTATE_IDX: [u8x32; 32] = [
60 u8x32(
61 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
62 25, 26, 27, 28, 29, 30, 31,
63 ),
64 u8x32(
65 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
66 24, 25, 26, 27, 28, 29, 30,
67 ),
68 u8x32(
69 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
70 23, 24, 25, 26, 27, 28, 29,
71 ),
72 u8x32(
73 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
74 22, 23, 24, 25, 26, 27, 28,
75 ),
76 u8x32(
77 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
78 21, 22, 23, 24, 25, 26, 27,
79 ),
80 u8x32(
81 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
82 20, 21, 22, 23, 24, 25, 26,
83 ),
84 u8x32(
85 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
86 19, 20, 21, 22, 23, 24, 25,
87 ),
88 u8x32(
89 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
90 18, 19, 20, 21, 22, 23, 24,
91 ),
92 u8x32(
93 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
94 17, 18, 19, 20, 21, 22, 23,
95 ),
96 u8x32(
97 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
98 16, 17, 18, 19, 20, 21, 22,
99 ),
100 u8x32(
101 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
102 15, 16, 17, 18, 19, 20, 21,
103 ),
104 u8x32(
105 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
106 14, 15, 16, 17, 18, 19, 20,
107 ),
108 u8x32(
109 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
110 13, 14, 15, 16, 17, 18, 19,
111 ),
112 u8x32(
113 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
114 12, 13, 14, 15, 16, 17, 18,
115 ),
116 u8x32(
117 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
118 11, 12, 13, 14, 15, 16, 17,
119 ),
120 u8x32(
121 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
122 10, 11, 12, 13, 14, 15, 16,
123 ),
124 u8x32(
125 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7, 8,
126 9, 10, 11, 12, 13, 14, 15,
127 ),
128 u8x32(
129 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5, 6, 7,
130 8, 9, 10, 11, 12, 13, 14,
131 ),
132 u8x32(
133 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4, 5,
134 6, 7, 8, 9, 10, 11, 12, 13,
135 ),
136 u8x32(
137 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3, 4,
138 5, 6, 7, 8, 9, 10, 11, 12,
139 ),
140 u8x32(
141 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1, 2, 3,
142 4, 5, 6, 7, 8, 9, 10, 11,
143 ),
144 u8x32(
145 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0, 1,
146 2, 3, 4, 5, 6, 7, 8, 9, 10,
147 ),
148 u8x32(
149 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 0,
150 1, 2, 3, 4, 5, 6, 7, 8, 9,
151 ),
152 u8x32(
153 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
154 0, 1, 2, 3, 4, 5, 6, 7, 8,
155 ),
156 u8x32(
157 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
158 31, 0, 1, 2, 3, 4, 5, 6, 7,
159 ),
160 u8x32(
161 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
162 30, 31, 0, 1, 2, 3, 4, 5, 6,
163 ),
164 u8x32(
165 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
166 30, 31, 0, 1, 2, 3, 4, 5,
167 ),
168 u8x32(
169 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
170 29, 30, 31, 0, 1, 2, 3, 4,
171 ),
172 u8x32(
173 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
174 28, 29, 30, 31, 0, 1, 2, 3,
175 ),
176 u8x32(
177 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
178 27, 28, 29, 30, 31, 0, 1, 2,
179 ),
180 u8x32(
181 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
182 27, 28, 29, 30, 31, 0, 1,
183 ),
184 u8x32(
185 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
186 26, 27, 28, 29, 30, 31, 0,
187 ),
188];
189
190static AVX2_128_ROTATE_IDX: [u8x16; 16] = [
191 u8x16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
192 u8x16(15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14),
193 u8x16(14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13),
194 u8x16(13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12),
195 u8x16(12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11),
196 u8x16(11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10),
197 u8x16(10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
198 u8x16(9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8),
199 u8x16(8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7),
200 u8x16(7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6),
201 u8x16(6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5),
202 u8x16(5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4),
203 u8x16(4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3),
204 u8x16(3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2),
205 u8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1),
206 u8x16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0),
207];
208
209static V3_U32_MASKS: [u32x8; 9] = [
210 u32x8(0, 0, 0, 0, 0, 0, 0, 0),
211 u32x8(!0, 0, 0, 0, 0, 0, 0, 0),
212 u32x8(!0, !0, 0, 0, 0, 0, 0, 0),
213 u32x8(!0, !0, !0, 0, 0, 0, 0, 0),
214 u32x8(!0, !0, !0, !0, 0, 0, 0, 0),
215 u32x8(!0, !0, !0, !0, !0, 0, 0, 0),
216 u32x8(!0, !0, !0, !0, !0, !0, 0, 0),
217 u32x8(!0, !0, !0, !0, !0, !0, !0, 0),
218 u32x8(!0, !0, !0, !0, !0, !0, !0, !0),
219];
220static V3_U32_LAST_MASKS: [u32x8; 9] = [
221 u32x8(0, 0, 0, 0, 0, 0, 0, 0),
222 u32x8(0, 0, 0, 0, 0, 0, 0, !0),
223 u32x8(0, 0, 0, 0, 0, 0, !0, !0),
224 u32x8(0, 0, 0, 0, 0, !0, !0, !0),
225 u32x8(0, 0, 0, 0, !0, !0, !0, !0),
226 u32x8(0, 0, 0, !0, !0, !0, !0, !0),
227 u32x8(0, 0, !0, !0, !0, !0, !0, !0),
228 u32x8(0, !0, !0, !0, !0, !0, !0, !0),
229 u32x8(!0, !0, !0, !0, !0, !0, !0, !0),
230];
231
232impl Seal for V3 {}
233impl Seal for V3_Scalar {}
234
235#[derive(Copy, Clone, Debug)]
236#[repr(transparent)]
237pub struct V3_Scalar(pub V3);
238
239#[cfg(target_arch = "x86_64")]
240#[inline(always)]
241pub(super) fn avx_load_u32s(simd: Avx2, slice: &[u32]) -> u32x8 {
242 _ = simd;
243 unsafe { avx_ld_u32s(slice.as_ptr(), LD_ST[2 * (16 * slice.len().min(8))]) }
244}
245
246#[cfg(target_arch = "x86_64")]
247#[inline(always)]
248pub(super) fn avx_store_u32s(simd: Avx2, slice: &mut [u32], value: u32x8) {
249 _ = simd;
250 unsafe {
251 avx_st_u32s(
252 slice.as_mut_ptr(),
253 value,
254 LD_ST[2 * (16 * slice.len().min(8)) + 1],
255 );
256 }
257}
258
259impl core::ops::Deref for V3 {
260 type Target = V2;
261
262 #[inline(always)]
263 fn deref(&self) -> &Self::Target {
264 V2 {
265 sse: self.sse,
266 sse2: self.sse2,
267 fxsr: self.fxsr,
268 sse3: self.sse3,
269 ssse3: self.ssse3,
270 sse4_1: self.sse4_1,
271 sse4_2: self.sse4_2,
272 popcnt: self.popcnt,
273 }
274 .to_ref()
275 }
276}
277
278macro_rules! splat {
279 ($ty: ty, $factor: literal) => {
280 paste! {
281 #[inline(always)]
282 fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>] {
283 self.[<splat_ $ty x $factor>](value)
284 }
285 }
286 };
287 ($($ty: ident x $factor: literal),*) => {
288 $(splat!($ty, $factor);)*
289 };
290}
291
292macro_rules! impl_simd_binop {
293 ($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
294 paste! {
295 #[inline(always)]
296 fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
297 self.[<$op _ $ty x $factor>](a, b)
298 }
299 }
300 };
301 ($func: ident, $op: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
302 $(impl_simd_binop!($func, $op, $ty, $out, $factor);)*
303 };
304 ($func: ident, $op: ident, $($ty: ident x $factor: literal),*) => {
305 $(impl_simd_binop!($func, $op, $ty, $ty, $factor);)*
306 };
307 ($func: ident, $($ty: ident x $factor: literal => $out: ty),*) => {
308 $(impl_simd_binop!($func, $func, $ty, $out, $factor);)*
309 };
310 ($func: ident, $($ty: ident x $factor: literal),*) => {
311 $(impl_simd_binop!($func, $func, $ty, $ty, $factor);)*
312 };
313}
314
315macro_rules! impl_simd_unop {
316 ($func: ident, $op: ident, $ty: ident, $out: ty, $factor: literal) => {
317 paste! {
318 #[inline(always)]
319 fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$out s>] {
320 self.[<$op _ $ty x $factor>](a)
321 }
322 }
323 };
324 ($func: ident, $($ty: ident x $factor: literal),*) => {
325 $(impl_simd_unop!($func, $func, $ty, $ty, $factor);)*
326 };
327}
328
329macro_rules! impl_scalar_binop {
330 ($func: ident, $ty: ident, $out: ty, impl) => {
331 paste! {
332 #[inline(always)]
333 fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
334 Scalar256b.[<$func _ $ty s>](a, b)
335 }
336 }
337 };
338 ($func: ident, $($ty: ident => $out: ty),*) => {
339 $(impl_scalar_binop!($func, $ty, $out, impl);)*
340 };
341 ($func: ident, $($ty: ident),*) => {
342 $(impl_scalar_binop!($func, $ty, $ty, impl);)*
343 };
344}
345
346impl Simd for V3 {
347 type c32s = f32x8;
348 type c64s = f64x4;
349 type f32s = f32x8;
350 type f64s = f64x4;
351 type i16s = i16x16;
352 type i32s = i32x8;
353 type i64s = i64x4;
354 type i8s = i8x32;
355 type m16s = m16x16;
356 type m32s = m32x8;
357 type m64s = m64x4;
358 type m8s = m8x32;
359 type u16s = u16x16;
360 type u32s = u32x8;
361 type u64s = u64x4;
362 type u8s = u8x32;
363
364 const REGISTER_COUNT: usize = 16;
365
366 impl_simd_binop!(add, f32 x 8, f64 x 4);
367
368 impl_simd_binop!(add, wrapping_add, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
369
370 impl_simd_binop!(sub, f32 x 8, f64 x 4);
371
372 impl_simd_binop!(sub, wrapping_sub, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
373
374 impl_simd_binop!(mul, f32 x 8, f64 x 4);
375
376 impl_simd_binop!(mul, wrapping_mul, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
377
378 impl_scalar_binop!(mul, u64, i64);
379
380 impl_simd_binop!(and, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
381
382 impl_simd_binop!(or, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
383
384 impl_simd_binop!(xor, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
385
386 impl_simd_binop!(div, f32 x 8, f64 x 4);
387
388 impl_simd_binop!(equal, cmp_eq, u8 x 32 => m8, u16 x 16 => m16, u32 x 8 => m32, u64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
389
390 impl_simd_binop!(greater_than, cmp_gt, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
391
392 impl_simd_binop!(greater_than_or_equal, cmp_ge, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
393
394 impl_simd_binop!(less_than, cmp_lt, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
395
396 impl_simd_binop!(less_than_or_equal, cmp_le, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
397
398 splat!(u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
399
400 impl_simd_binop!(max, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, f32 x 8, f64 x 4);
401
402 impl_scalar_binop!(max, u64, i64);
403
404 impl_simd_binop!(min, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, f32 x 8, f64 x 4);
405
406 impl_scalar_binop!(min, u64, i64);
407
408 impl_simd_unop!(not, m8 x 32, u8 x 32, m16 x 16, u16 x 16, m32 x 8, u32 x 8, m64 x 4, u64 x 4);
409
410 #[inline(always)]
411 fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
412 let sqr = self.mul_f32s(a, a);
413 let sqr_rev = self
414 .avx
415 ._mm256_shuffle_ps::<0b10_11_00_01>(cast!(sqr), cast!(sqr));
416 self.add_f32s(sqr, cast!(sqr_rev))
417 }
418
419 #[inline(always)]
420 fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
421 let sqr = self.mul_f64s(a, a);
422 let sqr_rev = self.avx._mm256_shuffle_pd::<0b0101>(cast!(sqr), cast!(sqr));
423 self.add_f64s(sqr, cast!(sqr_rev))
424 }
425
426 #[inline(always)]
427 fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
428 let max = self.abs_f32s(a);
429 let max_rev = self
430 .avx
431 ._mm256_shuffle_ps::<0b10_11_00_01>(cast!(a), cast!(a));
432 self.max_f32s(max, cast!(max_rev))
433 }
434
435 #[inline(always)]
436 fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
437 let max = self.abs_f64s(a);
438 let max_rev = self.avx._mm256_shuffle_pd::<0b0101>(cast!(max), cast!(max));
439 self.max_f64s(max, cast!(max_rev))
440 }
441
442 #[inline(always)]
443 fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
444 self.add_f32s(a, b)
445 }
446
447 #[inline(always)]
448 fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
449 self.add_f64s(a, b)
450 }
451
452 #[inline(always)]
453 fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s {
454 self.equal_f32s(a, b)
455 }
456
457 #[inline(always)]
458 fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s {
459 self.equal_f64s(a, b)
460 }
461
462 #[inline(always)]
463 fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
464 self.xor_f32s(a, self.splat_c32s(c32 { re: 0.0, im: -0.0 }))
465 }
466
467 #[inline(always)]
468 fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
469 self.xor_f64s(a, self.splat_c64s(c64 { re: 0.0, im: -0.0 }))
470 }
471
472 #[inline(always)]
473 fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
474 let ab = cast!(a);
475 let xy = cast!(b);
476
477 let yx = self.avx._mm256_permute_ps::<0b10_11_00_01>(xy);
478 let aa = self.avx._mm256_moveldup_ps(ab);
479 let bb = self.avx._mm256_movehdup_ps(ab);
480
481 cast!(
482 self.fma
483 ._mm256_fmsubadd_ps(aa, xy, self.fma._mm256_fmsubadd_ps(bb, yx, cast!(c)))
484 )
485 }
486
487 #[inline(always)]
488 fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
489 let ab = cast!(a);
490 let xy = cast!(b);
491
492 let yx = self.avx._mm256_permute_pd::<0b0101>(xy);
493 let aa = self.avx._mm256_unpacklo_pd(ab, ab);
494 let bb = self.avx._mm256_unpackhi_pd(ab, ab);
495
496 cast!(
497 self.fma
498 ._mm256_fmsubadd_pd(aa, xy, self.fma._mm256_fmsubadd_pd(bb, yx, cast!(c)))
499 )
500 }
501
502 #[inline(always)]
503 fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
504 let ab = cast!(a);
505 let xy = cast!(b);
506
507 let yx = self.avx._mm256_permute_ps::<0b10_11_00_01>(xy);
508 let aa = self.avx._mm256_moveldup_ps(ab);
509 let bb = self.avx._mm256_movehdup_ps(ab);
510
511 cast!(
512 self.fma
513 ._mm256_fmsubadd_ps(aa, xy, self.avx._mm256_mul_ps(bb, yx))
514 )
515 }
516
517 #[inline(always)]
518 fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
519 let ab = cast!(a);
520 let xy = cast!(b);
521
522 let yx = self.avx._mm256_permute_pd::<0b0101>(xy);
523 let aa = self.avx._mm256_unpacklo_pd(ab, ab);
524 let bb = self.avx._mm256_unpackhi_pd(ab, ab);
525
526 cast!(
527 self.fma
528 ._mm256_fmsubadd_pd(aa, xy, self.avx._mm256_mul_pd(bb, yx))
529 )
530 }
531
532 #[inline(always)]
533 fn deinterleave_shfl_f32s<T: Interleave>(self, values: T) -> T {
534 let avx = self.avx;
535
536 if const { core::mem::size_of::<T>() == 2 * core::mem::size_of::<Self::f32s>() } {
537 let values: [__m256d; 2] = unsafe { core::mem::transmute_copy(&values) };
538 let values = [
544 cast!(avx._mm256_unpacklo_ps(cast!(values[0]), cast!(values[1]))),
545 cast!(avx._mm256_unpackhi_ps(cast!(values[0]), cast!(values[1]))),
546 ];
547
548 let values = [
551 avx._mm256_unpacklo_pd(values[0], values[1]),
552 avx._mm256_unpackhi_pd(values[0], values[1]),
553 ];
554
555 unsafe { core::mem::transmute_copy(&values) }
556 } else if const { core::mem::size_of::<T>() == 4 * core::mem::size_of::<Self::f32s>() } {
557 let values: [__m256d; 4] = unsafe { core::mem::transmute_copy(&values) };
562
563 let values = [
568 cast!(avx._mm256_unpacklo_ps(cast!(values[0]), cast!(values[1]))),
569 cast!(avx._mm256_unpackhi_ps(cast!(values[0]), cast!(values[1]))),
570 cast!(avx._mm256_unpacklo_ps(cast!(values[2]), cast!(values[3]))),
571 cast!(avx._mm256_unpackhi_ps(cast!(values[2]), cast!(values[3]))),
572 ];
573
574 let values = [
575 avx._mm256_unpacklo_pd(values[0], values[1]),
576 avx._mm256_unpackhi_pd(values[0], values[1]),
577 avx._mm256_unpacklo_pd(values[2], values[3]),
578 avx._mm256_unpackhi_pd(values[2], values[3]),
579 ];
580
581 let values = [
586 avx._mm256_unpacklo_pd(values[0], values[2]),
587 avx._mm256_unpacklo_pd(values[1], values[3]),
588 avx._mm256_unpackhi_pd(values[0], values[2]),
589 avx._mm256_unpackhi_pd(values[1], values[3]),
590 ];
591
592 unsafe { core::mem::transmute_copy(&values) }
593 } else {
594 unsafe { deinterleave_fallback::<f32, Self::f32s, T>(values) }
595 }
596 }
597
598 #[inline(always)]
599 fn deinterleave_shfl_f64s<T: Interleave>(self, values: T) -> T {
600 let avx = self.avx;
601
602 if const { core::mem::size_of::<T>() == 2 * core::mem::size_of::<Self::f64s>() } {
603 let values: [__m256d; 2] = unsafe { core::mem::transmute_copy(&values) };
604 let values = [
605 avx._mm256_unpacklo_pd(values[0], values[1]),
606 avx._mm256_unpackhi_pd(values[0], values[1]),
607 ];
608 unsafe { core::mem::transmute_copy(&values) }
609 } else if const { core::mem::size_of::<T>() == 4 * core::mem::size_of::<Self::f64s>() } {
610 let values: [__m256d; 4] = unsafe { core::mem::transmute_copy(&values) };
611
612 let values: [__m256d; 4] = [
622 avx._mm256_unpacklo_pd(values[0], values[1]),
623 avx._mm256_unpackhi_pd(values[0], values[1]),
624 avx._mm256_unpacklo_pd(values[2], values[3]),
625 avx._mm256_unpackhi_pd(values[2], values[3]),
626 ];
627
628 let values = [
633 avx._mm256_permute2f128_pd::<0b0010_0000>(values[0], values[2]),
634 avx._mm256_permute2f128_pd::<0b0010_0000>(values[1], values[3]),
635 avx._mm256_permute2f128_pd::<0b0011_0001>(values[0], values[2]),
636 avx._mm256_permute2f128_pd::<0b0011_0001>(values[1], values[3]),
637 ];
638
639 unsafe { core::mem::transmute_copy(&values) }
640 } else {
641 unsafe { deinterleave_fallback::<f64, Self::f64s, T>(values) }
642 }
643 }
644
645 #[inline(always)]
646 fn interleave_shfl_f32s<T: Interleave>(self, values: T) -> T {
647 if const {
648 (core::mem::size_of::<T>() == 2 * core::mem::size_of::<Self::f32s>())
649 || (core::mem::size_of::<T>() == 4 * core::mem::size_of::<Self::f32s>())
650 } {
651 self.deinterleave_shfl_f32s(values)
653 } else {
654 unsafe { interleave_fallback::<f32, Self::f32s, T>(values) }
655 }
656 }
657
658 #[inline(always)]
659 fn interleave_shfl_f64s<T: Interleave>(self, values: T) -> T {
660 if const {
661 (core::mem::size_of::<T>() == 2 * core::mem::size_of::<Self::f64s>())
662 || (core::mem::size_of::<T>() == 4 * core::mem::size_of::<Self::f64s>())
663 } {
664 self.deinterleave_shfl_f64s(values)
666 } else {
667 unsafe { interleave_fallback::<f64, Self::f64s, T>(values) }
668 }
669 }
670
671 #[inline(always)]
672 fn mask_between_m32s(self, start: u32, end: u32) -> MemMask<Self::m32s> {
673 let start = start.min(8) as usize;
674 let end = end.min(8) as usize;
675 MemMask {
676 mask: self.and_m32s(
677 cast!(V3_U32_LAST_MASKS[8 - start]),
678 cast!(V3_U32_MASKS[end]),
679 ),
680 #[cfg(target_arch = "x86_64")]
681 load: Some(LD_ST[2 * (16 * end + start) + 0]),
682 #[cfg(target_arch = "x86_64")]
683 store: Some(LD_ST[2 * (16 * end + start) + 1]),
684 }
685 }
686
687 #[inline(always)]
688 fn mask_between_m64s(self, start: u64, end: u64) -> MemMask<Self::m64s> {
689 let start = (2 * start.min(4)) as usize;
690 let end = (2 * end.min(4)) as usize;
691 MemMask {
692 mask: self.and_m64s(
693 cast!(V3_U32_LAST_MASKS[8 - start]),
694 cast!(V3_U32_MASKS[end]),
695 ),
696 #[cfg(target_arch = "x86_64")]
697 load: Some(LD_ST[2 * (16 * end + start) + 0]),
698 #[cfg(target_arch = "x86_64")]
699 store: Some(LD_ST[2 * (16 * end + start) + 1]),
700 }
701 }
702
703 #[inline(always)]
707 unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
708 cast!(self.mask_load_ptr_u32s(mask, ptr as _))
709 }
710
711 #[inline(always)]
715 unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
716 cast!(self.mask_load_ptr_u64s(mask, ptr as _))
717 }
718
719 #[inline(always)]
723 unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
724 Scalar256b.mask_load_ptr_u8s(mask, ptr)
725 }
726
727 #[inline(always)]
731 unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
732 Scalar256b.mask_load_ptr_u16s(mask, ptr)
733 }
734
735 #[inline(always)]
739 unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
740 #[cfg(target_arch = "x86_64")]
741 if let Some(load) = mask.load {
742 return avx_ld_u32s(ptr, load);
743 }
744 cast!(self.avx2._mm256_maskload_epi32(ptr as _, cast!(mask.mask)))
745 }
746
747 #[inline(always)]
751 unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
752 #[cfg(target_arch = "x86_64")]
753 if let Some(load) = mask.load {
754 return cast!(avx_ld_u32s(ptr as _, load));
755 }
756 cast!(self.avx2._mm256_maskload_epi64(ptr as _, cast!(mask.mask)))
757 }
758
759 #[inline(always)]
763 unsafe fn mask_store_ptr_c32s(
764 self,
765 mask: MemMask<Self::m32s>,
766 ptr: *mut c32,
767 values: Self::c32s,
768 ) {
769 self.mask_store_ptr_u32s(mask, ptr as _, cast!(values))
770 }
771
772 #[inline(always)]
776 unsafe fn mask_store_ptr_c64s(
777 self,
778 mask: MemMask<Self::m64s>,
779 ptr: *mut c64,
780 values: Self::c64s,
781 ) {
782 self.mask_store_ptr_u64s(mask, ptr as _, cast!(values))
783 }
784
785 #[inline(always)]
789 unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
790 Scalar256b.mask_store_ptr_u8s(mask, ptr, values);
791 }
792
793 #[inline(always)]
797 unsafe fn mask_store_ptr_u16s(
798 self,
799 mask: MemMask<Self::m16s>,
800 ptr: *mut u16,
801 values: Self::u16s,
802 ) {
803 Scalar256b.mask_store_ptr_u16s(mask, ptr, values);
804 }
805
806 #[inline(always)]
810 unsafe fn mask_store_ptr_u32s(
811 self,
812 mask: MemMask<Self::m32s>,
813 ptr: *mut u32,
814 values: Self::u32s,
815 ) {
816 #[cfg(target_arch = "x86_64")]
817 if let Some(store) = mask.store {
818 return avx_st_u32s(ptr, values, store);
819 }
820 _mm256_maskstore_epi32(ptr as *mut i32, cast!(mask.mask), cast!(values))
821 }
822
823 #[inline(always)]
827 unsafe fn mask_store_ptr_u64s(
828 self,
829 mask: MemMask<Self::m64s>,
830 ptr: *mut u64,
831 values: Self::u64s,
832 ) {
833 self.mask_store_ptr_u32s(
834 MemMask {
835 mask: cast!(mask.mask),
836 #[cfg(target_arch = "x86_64")]
837 load: mask.load,
838 #[cfg(target_arch = "x86_64")]
839 store: mask.store,
840 },
841 ptr as _,
842 cast!(values),
843 )
844 }
845
846 #[inline(always)]
847 fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
848 let ab = cast!(a);
849 let xy = cast!(b);
850
851 let yx = self.avx._mm256_permute_ps::<0b10_11_00_01>(xy);
852 let aa = self.avx._mm256_moveldup_ps(ab);
853 let bb = self.avx._mm256_movehdup_ps(ab);
854
855 cast!(
856 self.fma
857 ._mm256_fmaddsub_ps(aa, xy, self.fma._mm256_fmaddsub_ps(bb, yx, cast!(c)))
858 )
859 }
860
861 #[inline(always)]
862 fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
863 let ab = cast!(a);
864 let xy = cast!(b);
865
866 let yx = self.avx._mm256_permute_pd::<0b0101>(xy);
867 let aa = self.avx._mm256_unpacklo_pd(ab, ab);
868 let bb = self.avx._mm256_unpackhi_pd(ab, ab);
869
870 cast!(
871 self.fma
872 ._mm256_fmaddsub_pd(aa, xy, self.fma._mm256_fmaddsub_pd(bb, yx, cast!(c)))
873 )
874 }
875
876 #[inline(always)]
877 fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
878 self.mul_add_f32s(a, b, c)
879 }
880
881 #[inline(always)]
882 fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
883 self.mul_add_f64s(a, b, c)
884 }
885
886 #[inline(always)]
887 fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
888 cast!(self.fma._mm256_fmadd_ps(cast!(a), cast!(b), cast!(c)))
889 }
890
891 #[inline(always)]
892 fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
893 cast!(self.fma._mm256_fmadd_pd(cast!(a), cast!(b), cast!(c)))
894 }
895
896 #[inline(always)]
897 fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
898 self.negate_mul_add_f32s(a, b, c)
899 }
900
901 #[inline(always)]
902 fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
903 self.negate_mul_add_f64s(a, b, c)
904 }
905
906 #[inline(always)]
907 fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
908 cast!(self.fma._mm256_fnmadd_ps(cast!(a), cast!(b), cast!(c)))
909 }
910
911 #[inline(always)]
912 fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
913 cast!(self.fma._mm256_fnmadd_pd(cast!(a), cast!(b), cast!(c)))
914 }
915
916 #[inline(always)]
917 fn mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
918 let ab = cast!(a);
919 let xy = cast!(b);
920
921 let yx = self.avx._mm256_permute_ps::<0b10_11_00_01>(xy);
922 let aa = self.avx._mm256_moveldup_ps(ab);
923 let bb = self.avx._mm256_movehdup_ps(ab);
924
925 cast!(
926 self.fma
927 ._mm256_fmaddsub_ps(aa, xy, self.avx._mm256_mul_ps(bb, yx))
928 )
929 }
930
931 #[inline(always)]
932 fn mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
933 let ab = cast!(a);
934 let xy = cast!(b);
935
936 let yx = self.avx._mm256_permute_pd::<0b0101>(xy);
937 let aa = self.avx._mm256_unpacklo_pd(ab, ab);
938 let bb = self.avx._mm256_unpackhi_pd(ab, ab);
939
940 cast!(
941 self.fma
942 ._mm256_fmaddsub_pd(aa, xy, self.avx._mm256_mul_pd(bb, yx))
943 )
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 #[cfg(target_arch = "x86_64")]
957 #[inline(always)]
958 fn partial_load_u32s(self, slice: &[u32]) -> Self::u32s {
959 avx_load_u32s(self.avx2, slice)
960 }
961
962 #[cfg(target_arch = "x86_64")]
963 #[inline(always)]
964 fn partial_load_u64s(self, slice: &[u64]) -> Self::u64s {
965 cast!(self.partial_load_u32s(bytemuck::cast_slice(slice)))
966 }
967
968 #[cfg(target_arch = "x86_64")]
969 #[inline(always)]
970 fn partial_store_u32s(self, slice: &mut [u32], values: Self::u32s) {
971 avx_store_u32s(self.avx2, slice, values)
972 }
973
974 #[cfg(target_arch = "x86_64")]
975 #[inline(always)]
976 fn partial_store_u64s(self, slice: &mut [u64], values: Self::u64s) {
977 self.partial_store_u32s(bytemuck::cast_slice_mut(slice), cast!(values))
978 }
979
980 #[inline(always)]
981 fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
982 let a: __m256 = cast!(a);
983 let r = self.sse._mm_max_ps(
984 self.avx._mm256_castps256_ps128(a),
985 self.avx._mm256_extractf128_ps::<1>(a),
986 );
987 (*self).reduce_max_c32x2(cast!(r))
988 }
989
990 #[inline(always)]
991 fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
992 let a: __m256d = cast!(a);
993 let r = self.sse2._mm_max_pd(
994 self.avx._mm256_castpd256_pd128(a),
995 self.avx._mm256_extractf128_pd::<1>(a),
996 );
997 (*self).reduce_max_c64x1(cast!(r))
998 }
999
1000 #[inline(always)]
1001 fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
1002 let a: __m256 = cast!(a);
1003 let r = self.sse._mm_max_ps(
1004 self.avx._mm256_castps256_ps128(a),
1005 self.avx._mm256_extractf128_ps::<1>(a),
1006 );
1007 (*self).reduce_max_f32x4(cast!(r))
1008 }
1009
1010 #[inline(always)]
1011 fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
1012 let a: __m256d = cast!(a);
1013 let r = self.sse2._mm_max_pd(
1014 self.avx._mm256_castpd256_pd128(a),
1015 self.avx._mm256_extractf128_pd::<1>(a),
1016 );
1017 (*self).reduce_max_f64x2(cast!(r))
1018 }
1019
1020 #[inline(always)]
1021 fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
1022 let a: __m256 = cast!(a);
1023 let r = self.sse._mm_min_ps(
1024 self.avx._mm256_castps256_ps128(a),
1025 self.avx._mm256_extractf128_ps::<1>(a),
1026 );
1027 (*self).reduce_min_c32x2(cast!(r))
1028 }
1029
1030 #[inline(always)]
1031 fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
1032 let a: __m256d = cast!(a);
1033 let r = self.sse2._mm_min_pd(
1034 self.avx._mm256_castpd256_pd128(a),
1035 self.avx._mm256_extractf128_pd::<1>(a),
1036 );
1037 (*self).reduce_min_c64x1(cast!(r))
1038 }
1039
1040 #[inline(always)]
1041 fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
1042 let a: __m256 = cast!(a);
1043 let r = self.sse._mm_min_ps(
1044 self.avx._mm256_castps256_ps128(a),
1045 self.avx._mm256_extractf128_ps::<1>(a),
1046 );
1047 (*self).reduce_min_f32x4(cast!(r))
1048 }
1049
1050 #[inline(always)]
1051 fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
1052 let a: __m256d = cast!(a);
1053 let r = self.sse2._mm_min_pd(
1054 self.avx._mm256_castpd256_pd128(a),
1055 self.avx._mm256_extractf128_pd::<1>(a),
1056 );
1057 (*self).reduce_min_f64x2(cast!(r))
1058 }
1059
1060 #[inline(always)]
1061 fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
1062 let a: __m256 = cast!(a);
1063 let r = self.sse._mm_mul_ps(
1064 self.avx._mm256_castps256_ps128(a),
1065 self.avx._mm256_extractf128_ps::<1>(a),
1066 );
1067 (*self).reduce_product_f32x4(cast!(r))
1068 }
1069
1070 #[inline(always)]
1071 fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
1072 let a: __m256d = cast!(a);
1073 let r = self.sse2._mm_mul_pd(
1074 self.avx._mm256_castpd256_pd128(a),
1075 self.avx._mm256_extractf128_pd::<1>(a),
1076 );
1077 (*self).reduce_product_f64x2(cast!(r))
1078 }
1079
1080 #[inline(always)]
1081 fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
1082 let a: __m256 = cast!(a);
1083 let r = self.sse._mm_add_ps(
1084 self.avx._mm256_castps256_ps128(a),
1085 self.avx._mm256_extractf128_ps::<1>(a),
1086 );
1087 (*self).reduce_sum_c32x2(cast!(r))
1088 }
1089
1090 #[inline(always)]
1091 fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
1092 let a: __m256d = cast!(a);
1093 let r = self.sse2._mm_add_pd(
1094 self.avx._mm256_castpd256_pd128(a),
1095 self.avx._mm256_extractf128_pd::<1>(a),
1096 );
1097 (*self).reduce_sum_c64x1(cast!(r))
1098 }
1099
1100 #[inline(always)]
1101 fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
1102 let a: __m256 = cast!(a);
1103 let r = self.sse._mm_add_ps(
1104 self.avx._mm256_castps256_ps128(a),
1105 self.avx._mm256_extractf128_ps::<1>(a),
1106 );
1107 (*self).reduce_sum_f32x4(cast!(r))
1108 }
1109
1110 #[inline(always)]
1111 fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
1112 let a: __m256d = cast!(a);
1113 let r = self.sse2._mm_add_pd(
1114 self.avx._mm256_castpd256_pd128(a),
1115 self.avx._mm256_extractf128_pd::<1>(a),
1116 );
1117 (*self).reduce_sum_f64x2(cast!(r))
1118 }
1119
1120 #[inline(always)]
1121 fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
1122 cast!(avx2_pshufb(
1123 self,
1124 cast!(a),
1125 cast!(AVX2_ROTATE_IDX[8 * (amount % 4)]),
1126 ))
1127 }
1128
1129 #[inline(always)]
1130 fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
1131 cast!(avx2_pshufb(
1132 self,
1133 cast!(a),
1134 cast!(AVX2_ROTATE_IDX[16 * (amount % 2)]),
1135 ))
1136 }
1137
1138 #[inline(always)]
1139 fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
1140 cast!(avx2_pshufb(
1141 self,
1142 cast!(a),
1143 cast!(AVX2_ROTATE_IDX[4 * (amount % 8)]),
1144 ))
1145 }
1146
1147 #[inline(always)]
1148 fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
1149 cast!(avx2_pshufb(
1150 self,
1151 cast!(a),
1152 cast!(AVX2_ROTATE_IDX[8 * (amount % 4)]),
1153 ))
1154 }
1155
1156 #[inline(always)]
1157 fn select_u32s(
1158 self,
1159 mask: Self::m32s,
1160 if_true: Self::u32s,
1161 if_false: Self::u32s,
1162 ) -> Self::u32s {
1163 let mask: __m256 = cast!(mask);
1164 let if_true: __m256 = cast!(if_true);
1165 let if_false: __m256 = cast!(if_false);
1166
1167 cast!(self.avx._mm256_blendv_ps(if_false, if_true, mask))
1168 }
1169
1170 #[inline(always)]
1171 fn select_u64s(
1172 self,
1173 mask: Self::m64s,
1174 if_true: Self::u64s,
1175 if_false: Self::u64s,
1176 ) -> Self::u64s {
1177 let mask: __m256d = cast!(mask);
1178 let if_true: __m256d = cast!(if_true);
1179 let if_false: __m256d = cast!(if_false);
1180
1181 cast!(self.avx._mm256_blendv_pd(if_false, if_true, mask))
1182 }
1183
1184 #[inline(always)]
1185 fn splat_c32s(self, value: c32) -> Self::c32s {
1186 cast!(self.splat_f64s(cast!(value)))
1187 }
1188
1189 #[inline(always)]
1190 fn splat_c64s(self, value: c64) -> Self::c64s {
1191 cast!(self.avx._mm256_broadcast_pd(&cast!(value)))
1192 }
1193
1194 #[inline(always)]
1195 fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1196 self.sub_f32s(a, b)
1197 }
1198
1199 #[inline(always)]
1200 fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1201 self.sub_f64s(a, b)
1202 }
1203
1204 #[inline(always)]
1205 fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
1206 cast!(self.avx._mm256_permute_ps::<0b10_11_00_01>(cast!(a)))
1207 }
1208
1209 #[inline(always)]
1210 fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
1211 cast!(self.avx._mm256_permute_pd::<0b0101>(cast!(a)))
1212 }
1213
1214 #[inline(always)]
1215 fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
1216 struct Impl<Op> {
1217 this: V3,
1218 op: Op,
1219 }
1220 impl<Op: WithSimd> crate::NullaryFnOnce for Impl<Op> {
1221 type Output = Op::Output;
1222
1223 #[inline(always)]
1224 fn call(self) -> Self::Output {
1225 self.op.with_simd(self.this)
1226 }
1227 }
1228 self.vectorize(Impl { this: self, op })
1229 }
1230
1231 #[inline(always)]
1232 fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
1233 self.widening_mul_u32x8(a, b)
1234 }
1235
1236 #[inline(always)]
1237 fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1238 self.shl_dyn_u32x8(a, self.and_u32x8(amount, self.splat_u32x8(32 - 1)))
1239 }
1240
1241 #[inline(always)]
1242 fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1243 self.shr_dyn_u32x8(a, self.and_u32x8(amount, self.splat_u32x8(32 - 1)))
1244 }
1245
1246 #[inline(always)]
1247 fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
1248 self.sqrt_f32x8(a)
1249 }
1250
1251 #[inline(always)]
1252 fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
1253 self.sqrt_f64x4(a)
1254 }
1255}
1256
1257#[derive(Copy, Clone, Debug)]
1258#[repr(transparent)]
1259pub struct V3_128b(pub V3);
1260
1261#[derive(Copy, Clone, Debug)]
1262#[repr(transparent)]
1263pub struct V3_256b(pub V3);
1264
1265#[derive(Copy, Clone, Debug)]
1266#[repr(transparent)]
1267pub struct V3_512b(pub V3);
1268
1269impl core::ops::Deref for V3_128b {
1270 type Target = V3;
1271
1272 #[inline]
1273 fn deref(&self) -> &Self::Target {
1274 &self.0
1275 }
1276}
1277
1278impl core::ops::Deref for V3_256b {
1279 type Target = V3;
1280
1281 #[inline]
1282 fn deref(&self) -> &Self::Target {
1283 &self.0
1284 }
1285}
1286
1287impl core::ops::Deref for V3_512b {
1288 type Target = V3;
1289
1290 #[inline]
1291 fn deref(&self) -> &Self::Target {
1292 &self.0
1293 }
1294}
1295
1296impl Seal for V3_128b {}
1297impl Seal for V3_256b {}
1298impl Seal for V3_512b {}
1299
1300macro_rules! impl_scalar_binop {
1301 ($func: ident, $ty: ident, $out: ty, impl) => {
1302 paste! {
1303 #[inline(always)]
1304 fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
1305 Scalar128b.[<$func _ $ty s>](a, b)
1306 }
1307 }
1308 };
1309 ($func: ident, $($ty: ident => $out: ty),*) => {
1310 $(impl_scalar_binop!($func, $ty, $out, impl);)*
1311 };
1312 ($func: ident, $($ty: ident),*) => {
1313 $(impl_scalar_binop!($func, $ty, $ty, impl);)*
1314 };
1315}
1316
1317impl Simd for V3_128b {
1318 type c32s = f32x4;
1319 type c64s = f64x2;
1320 type f32s = f32x4;
1321 type f64s = f64x2;
1322 type i16s = i16x8;
1323 type i32s = i32x4;
1324 type i64s = i64x2;
1325 type i8s = i8x16;
1326 type m16s = m16x8;
1327 type m32s = m32x4;
1328 type m64s = m64x2;
1329 type m8s = m8x16;
1330 type u16s = u16x8;
1331 type u32s = u32x4;
1332 type u64s = u64x2;
1333 type u8s = u8x16;
1334
1335 const REGISTER_COUNT: usize = 16;
1336
1337 impl_simd_binop!(add, f32 x 4, f64 x 2);
1338
1339 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);
1340
1341 impl_simd_binop!(sub, f32 x 4, f64 x 2);
1342
1343 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);
1344
1345 impl_simd_binop!(mul, f32 x 4, f64 x 2);
1346
1347 impl_simd_binop!(mul, wrapping_mul, u16 x 8, i16 x 8, u32 x 4, i32 x 4);
1348
1349 impl_scalar_binop!(mul, u64, i64);
1350
1351 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);
1352
1353 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);
1354
1355 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);
1356
1357 impl_simd_binop!(div, f32 x 4, f64 x 2);
1358
1359 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);
1360
1361 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);
1362
1363 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);
1364
1365 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);
1366
1367 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);
1368
1369 impl_scalar_binop!(conj_mul, c32, c64);
1370
1371 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);
1372
1373 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);
1374
1375 impl_scalar_binop!(max, u64, i64);
1376
1377 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);
1378
1379 impl_scalar_binop!(min, u64, i64);
1380
1381 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);
1382
1383 #[inline(always)]
1384 fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
1385 let sqr = self.mul_f32s(a, a);
1386 let sqr_rev = self
1387 .sse
1388 ._mm_shuffle_ps::<0b10_11_00_01>(cast!(sqr), cast!(sqr));
1389 self.add_f32s(sqr, cast!(sqr_rev))
1390 }
1391
1392 #[inline(always)]
1393 fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
1394 let sqr = self.mul_f64s(a, a);
1395 let sqr_rev = self.sse2._mm_shuffle_pd::<0b01>(cast!(sqr), cast!(sqr));
1396 self.add_f64s(sqr, cast!(sqr_rev))
1397 }
1398
1399 #[inline(always)]
1400 fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
1401 let sqr = self.abs_f32s(a);
1402 let sqr_rev = self
1403 .sse
1404 ._mm_shuffle_ps::<0b10_11_00_01>(cast!(sqr), cast!(sqr));
1405 self.max_f32s(sqr, cast!(sqr_rev))
1406 }
1407
1408 #[inline(always)]
1409 fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
1410 let sqr = self.abs_f64s(a);
1411 let sqr_rev = self.sse2._mm_shuffle_pd::<0b01>(cast!(sqr), cast!(sqr));
1412 self.max_f64s(sqr, cast!(sqr_rev))
1413 }
1414
1415 #[inline(always)]
1416 fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1417 self.add_f32s(a, b)
1418 }
1419
1420 #[inline(always)]
1421 fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1422 self.add_f64s(a, b)
1423 }
1424
1425 #[inline(always)]
1426 fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s {
1427 self.equal_f32s(a, b)
1428 }
1429
1430 #[inline(always)]
1431 fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s {
1432 self.equal_f64s(a, b)
1433 }
1434
1435 #[inline(always)]
1436 fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
1437 self.xor_f32s(a, self.splat_c32s(c32 { re: 0.0, im: -0.0 }))
1438 }
1439
1440 #[inline(always)]
1441 fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
1442 self.xor_f64s(a, self.splat_c64s(c64 { re: 0.0, im: -0.0 }))
1443 }
1444
1445 #[inline(always)]
1446 fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
1447 let ab = cast!(a);
1448 let xy = cast!(b);
1449
1450 let yx = self.avx._mm_permute_ps::<0b10_11_00_01>(xy);
1451 let aa = self.sse3._mm_moveldup_ps(ab);
1452 let bb = self.sse3._mm_movehdup_ps(ab);
1453
1454 cast!(
1455 self.fma
1456 ._mm_fmsubadd_ps(aa, xy, self.fma._mm_fmsubadd_ps(bb, yx, cast!(c)))
1457 )
1458 }
1459
1460 #[inline(always)]
1461 fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
1462 let ab = cast!(a);
1463 let xy = cast!(b);
1464
1465 let yx = self.avx._mm_permute_pd::<0b01>(xy);
1466 let aa = self.sse2._mm_unpacklo_pd(ab, ab);
1467 let bb = self.sse2._mm_unpackhi_pd(ab, ab);
1468
1469 cast!(
1470 self.fma
1471 ._mm_fmsubadd_pd(aa, xy, self.fma._mm_fmsubadd_pd(bb, yx, cast!(c)))
1472 )
1473 }
1474
1475 #[inline(always)]
1476 unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
1477 cast!(self.mask_load_ptr_u32s(mask, ptr as _))
1478 }
1479
1480 #[inline(always)]
1481 unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
1482 cast!(self.mask_load_ptr_u64s(mask, ptr as _))
1483 }
1484
1485 #[inline(always)]
1486 unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
1487 Scalar128b.mask_load_ptr_u8s(mask, ptr)
1488 }
1489
1490 #[inline(always)]
1491 unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
1492 Scalar128b.mask_load_ptr_u16s(mask, ptr)
1493 }
1494
1495 #[inline(always)]
1496 unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
1497 #[cfg(target_arch = "x86_64")]
1498 if let Some(load) = mask.load {
1499 return cast_lossy(avx_ld_u32s(ptr, load));
1500 }
1501 cast!(self.avx2._mm_maskload_epi32(ptr as _, cast!(mask.mask)))
1502 }
1503
1504 #[inline(always)]
1505 unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
1506 #[cfg(target_arch = "x86_64")]
1507 if let Some(load) = mask.load {
1508 return cast_lossy(avx_ld_u32s(ptr as _, load));
1509 }
1510 cast!(self.avx2._mm_maskload_epi64(ptr as _, cast!(mask.mask)))
1511 }
1512
1513 #[inline(always)]
1514 unsafe fn mask_store_ptr_c32s(
1515 self,
1516 mask: MemMask<Self::m32s>,
1517 ptr: *mut c32,
1518 values: Self::c32s,
1519 ) {
1520 self.mask_store_ptr_u32s(mask, ptr as _, cast!(values));
1521 }
1522
1523 #[inline(always)]
1524 unsafe fn mask_store_ptr_c64s(
1525 self,
1526 mask: MemMask<Self::m64s>,
1527 ptr: *mut c64,
1528 values: Self::c64s,
1529 ) {
1530 self.mask_store_ptr_u64s(mask, ptr as _, cast!(values))
1531 }
1532
1533 #[inline(always)]
1534 unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
1535 Scalar128b.mask_store_ptr_u8s(mask, ptr, values);
1536 }
1537
1538 #[inline(always)]
1539 unsafe fn mask_store_ptr_u16s(
1540 self,
1541 mask: MemMask<Self::m16s>,
1542 ptr: *mut u16,
1543 values: Self::u16s,
1544 ) {
1545 Scalar128b.mask_store_ptr_u16s(mask, ptr, values);
1546 }
1547
1548 #[inline(always)]
1549 unsafe fn mask_store_ptr_u32s(
1550 self,
1551 mask: MemMask<Self::m32s>,
1552 ptr: *mut u32,
1553 values: Self::u32s,
1554 ) {
1555 #[cfg(target_arch = "x86_64")]
1556 if let Some(store) = mask.store {
1557 return avx_st_u32s(ptr, cast!([values, self.splat_u32s(0)]), store);
1558 }
1559 self.avx2
1560 ._mm_maskstore_epi32(ptr as _, cast!(mask.mask), cast!(values));
1561 }
1562
1563 #[inline(always)]
1564 unsafe fn mask_store_ptr_u64s(
1565 self,
1566 mask: MemMask<Self::m64s>,
1567 ptr: *mut u64,
1568 values: Self::u64s,
1569 ) {
1570 self.mask_store_ptr_u32s(
1571 MemMask {
1572 mask: cast!(mask.mask),
1573 #[cfg(target_arch = "x86_64")]
1574 load: mask.load,
1575 #[cfg(target_arch = "x86_64")]
1576 store: mask.store,
1577 },
1578 ptr as _,
1579 cast!(values),
1580 )
1581 }
1582
1583 #[inline(always)]
1584 fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
1585 let ab = cast!(a);
1586 let xy = cast!(b);
1587
1588 let yx = self.avx._mm_permute_ps::<0b10_11_00_01>(xy);
1589 let aa = self.sse3._mm_moveldup_ps(ab);
1590 let bb = self.sse3._mm_movehdup_ps(ab);
1591
1592 cast!(
1593 self.fma
1594 ._mm_fmaddsub_ps(aa, xy, self.fma._mm_fmaddsub_ps(bb, yx, cast!(c)))
1595 )
1596 }
1597
1598 #[inline(always)]
1599 fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
1600 let ab = cast!(a);
1601 let xy = cast!(b);
1602
1603 let yx = self.avx._mm_permute_pd::<0b01>(xy);
1604 let aa = self.sse2._mm_unpacklo_pd(ab, ab);
1605 let bb = self.sse2._mm_unpackhi_pd(ab, ab);
1606
1607 cast!(
1608 self.fma
1609 ._mm_fmaddsub_pd(aa, xy, self.fma._mm_fmaddsub_pd(bb, yx, cast!(c)))
1610 )
1611 }
1612
1613 #[inline(always)]
1614 fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1615 self.mul_add_f32s(a, b, c)
1616 }
1617
1618 #[inline(always)]
1619 fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1620 self.mul_add_f64s(a, b, c)
1621 }
1622
1623 #[inline(always)]
1624 fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1625 self.mul_add_f32x4(a, b, c)
1626 }
1627
1628 #[inline(always)]
1629 fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1630 self.mul_add_f64x2(a, b, c)
1631 }
1632
1633 #[inline(always)]
1634 fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1635 self.negate_mul_add_f32s(a, b, c)
1636 }
1637
1638 #[inline(always)]
1639 fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1640 self.negate_mul_add_f64s(a, b, c)
1641 }
1642
1643 #[inline(always)]
1644 fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1645 self.negate_mul_add_f32x4(a, b, c)
1646 }
1647
1648 #[inline(always)]
1649 fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1650 self.negate_mul_add_f64x2(a, b, c)
1651 }
1652
1653 #[inline(always)]
1654 fn mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1655 let ab = cast!(a);
1656 let xy = cast!(b);
1657
1658 let yx = self.avx._mm_permute_ps::<0b10_11_00_01>(xy);
1659 let aa = self.sse3._mm_moveldup_ps(ab);
1660 let bb = self.sse3._mm_movehdup_ps(ab);
1661
1662 cast!(
1663 self.fma
1664 ._mm_fmaddsub_ps(aa, xy, self.sse._mm_mul_ps(bb, yx))
1665 )
1666 }
1667
1668 #[inline(always)]
1669 fn mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1670 let ab = cast!(a);
1671 let xy = cast!(b);
1672
1673 let yx = self.avx._mm_permute_pd::<0b01>(xy);
1674 let aa = self.sse2._mm_unpacklo_pd(ab, ab);
1675 let bb = self.sse2._mm_unpackhi_pd(ab, ab);
1676
1677 cast!(
1678 self.fma
1679 ._mm_fmaddsub_pd(aa, xy, self.sse2._mm_mul_pd(bb, yx))
1680 )
1681 }
1682
1683 #[inline(always)]
1684 fn neg_c32s(self, a: Self::c32s) -> Self::c32s {
1685 self.xor_f32s(a, self.splat_f32s(-0.0))
1686 }
1687
1688 #[inline(always)]
1689 fn neg_c64s(self, a: Self::c64s) -> Self::c64s {
1690 self.xor_f64s(a, self.splat_f64s(-0.0))
1691 }
1692
1693 #[cfg(target_arch = "x86_64")]
1694 #[inline(always)]
1695 fn partial_load_u32s(self, slice: &[u32]) -> Self::u32s {
1696 cast_lossy(avx_load_u32s(self.avx2, slice))
1697 }
1698
1699 #[cfg(target_arch = "x86_64")]
1700 #[inline(always)]
1701 fn partial_load_u64s(self, slice: &[u64]) -> Self::u64s {
1702 cast!(self.partial_load_u32s(bytemuck::cast_slice(slice)))
1703 }
1704
1705 #[cfg(target_arch = "x86_64")]
1706 #[inline(always)]
1707 fn partial_store_u32s(self, slice: &mut [u32], values: Self::u32s) {
1708 avx_store_u32s(self.avx2, slice, cast!([values, self.splat_u32s(0)]))
1709 }
1710
1711 #[cfg(target_arch = "x86_64")]
1712 #[inline(always)]
1713 fn partial_store_u64s(self, slice: &mut [u64], values: Self::u64s) {
1714 self.partial_store_u32s(bytemuck::cast_slice_mut(slice), cast!(values))
1715 }
1716
1717 #[inline(always)]
1718 fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
1719 let a: __m128 = cast!(a);
1720 let hi = self.sse._mm_movehl_ps(a, a);
1721 let r0 = self.sse._mm_max_ps(a, hi);
1722 cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
1723 }
1724
1725 #[inline(always)]
1726 fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
1727 cast!(a)
1728 }
1729
1730 #[inline(always)]
1731 fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
1732 let a: __m128 = cast!(a);
1733 let hi = self.sse._mm_movehl_ps(a, a);
1734 let r0 = self.sse._mm_max_ps(a, hi);
1735 let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
1736 let r = self.sse._mm_max_ss(r0, r0_shuffled);
1737 self.sse._mm_cvtss_f32(r)
1738 }
1739
1740 #[inline(always)]
1741 fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
1742 let a: __m128d = cast!(a);
1743 let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
1744 let r = self.sse2._mm_max_sd(a, hi);
1745 self.sse2._mm_cvtsd_f64(r)
1746 }
1747
1748 #[inline(always)]
1749 fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
1750 let a: __m128 = cast!(a);
1751 let hi = self.sse._mm_movehl_ps(a, a);
1752 let r0 = self.sse._mm_min_ps(a, hi);
1753 cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
1754 }
1755
1756 #[inline(always)]
1757 fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
1758 cast!(a)
1759 }
1760
1761 #[inline(always)]
1762 fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
1763 let a: __m128 = cast!(a);
1764 let hi = self.sse._mm_movehl_ps(a, a);
1765 let r0 = self.sse._mm_min_ps(a, hi);
1766 let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
1767 let r = self.sse._mm_min_ss(r0, r0_shuffled);
1768 self.sse._mm_cvtss_f32(r)
1769 }
1770
1771 #[inline(always)]
1772 fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
1773 let a: __m128d = cast!(a);
1774 let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
1775 let r = self.sse2._mm_min_sd(a, hi);
1776 self.sse2._mm_cvtsd_f64(r)
1777 }
1778
1779 #[inline(always)]
1780 fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
1781 let a: __m128 = cast!(a);
1782 let hi = self.sse._mm_movehl_ps(a, a);
1783 let r0 = self.sse._mm_mul_ps(a, hi);
1784 let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
1785 let r = self.sse._mm_mul_ss(r0, r0_shuffled);
1786 self.sse._mm_cvtss_f32(r)
1787 }
1788
1789 #[inline(always)]
1790 fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
1791 let a: __m128d = cast!(a);
1792 let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
1793 let r = self.sse2._mm_mul_sd(a, hi);
1794 self.sse2._mm_cvtsd_f64(r)
1795 }
1796
1797 #[inline(always)]
1798 fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
1799 let a: __m128 = cast!(a);
1801 let hi = self.sse._mm_movehl_ps(a, a);
1803
1804 let r0 = self.sse._mm_add_ps(a, hi);
1806
1807 cast!(self.sse2._mm_cvtsd_f64(cast!(r0)))
1808 }
1809
1810 #[inline(always)]
1811 fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
1812 cast!(a)
1813 }
1814
1815 #[inline(always)]
1816 fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
1817 let a: __m128 = cast!(a);
1818 let hi = self.sse._mm_movehl_ps(a, a);
1819 let r0 = self.sse._mm_add_ps(a, hi);
1820 let r0_shuffled = self.sse._mm_shuffle_ps::<0b0001>(r0, r0);
1821 let r = self.sse._mm_add_ss(r0, r0_shuffled);
1822 self.sse._mm_cvtss_f32(r)
1823 }
1824
1825 #[inline(always)]
1826 fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
1827 let a: __m128d = cast!(a);
1828 let hi = cast!(self.sse._mm_movehl_ps(cast!(a), cast!(a)));
1829 let r = self.sse2._mm_add_sd(a, hi);
1830 self.sse2._mm_cvtsd_f64(r)
1831 }
1832
1833 #[inline(always)]
1834 fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
1835 cast!(
1836 self.ssse3
1837 ._mm_shuffle_epi8(cast!(a), cast!(AVX2_128_ROTATE_IDX[8 * (amount % 2)]))
1838 )
1839 }
1840
1841 #[inline(always)]
1842 fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
1843 _ = amount;
1844 a
1845 }
1846
1847 #[inline(always)]
1848 fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
1849 cast!(
1850 self.ssse3
1851 ._mm_shuffle_epi8(cast!(a), cast!(AVX2_128_ROTATE_IDX[4 * (amount % 4)]))
1852 )
1853 }
1854
1855 #[inline(always)]
1856 fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
1857 cast!(
1858 self.ssse3
1859 ._mm_shuffle_epi8(cast!(a), cast!(AVX2_128_ROTATE_IDX[8 * (amount % 2)]))
1860 )
1861 }
1862
1863 #[inline(always)]
1864 fn select_u32s(
1865 self,
1866 mask: Self::m32s,
1867 if_true: Self::u32s,
1868 if_false: Self::u32s,
1869 ) -> Self::u32s {
1870 self.select_u32x4(mask, if_true, if_false)
1871 }
1872
1873 #[inline(always)]
1874 fn select_u64s(
1875 self,
1876 mask: Self::m64s,
1877 if_true: Self::u64s,
1878 if_false: Self::u64s,
1879 ) -> Self::u64s {
1880 self.select_u64x2(mask, if_true, if_false)
1881 }
1882
1883 #[inline(always)]
1884 fn splat_c32s(self, value: c32) -> Self::c32s {
1885 cast!(self.splat_f64x2(cast!(value)))
1886 }
1887
1888 #[inline(always)]
1889 fn splat_c64s(self, value: c64) -> Self::c64s {
1890 cast!(value)
1891 }
1892
1893 #[inline(always)]
1894 fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1895 self.sub_f32x4(a, b)
1896 }
1897
1898 #[inline(always)]
1899 fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1900 self.sub_f64x2(a, b)
1901 }
1902
1903 #[inline(always)]
1904 fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
1905 cast!(self.avx._mm_permute_ps::<0b10_11_00_01>(cast!(a)))
1906 }
1907
1908 #[inline(always)]
1909 fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
1910 cast!(self.avx._mm_permute_pd::<0b01>(cast!(a)))
1911 }
1912
1913 #[inline(always)]
1914 fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
1915 Simd::vectorize(self.0, op)
1916 }
1917
1918 #[inline(always)]
1919 fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
1920 self.widening_mul_u32x4(a, b)
1921 }
1922
1923 #[inline(always)]
1924 fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1925 self.shl_dyn_u32x4(a, self.and_u32x4(amount, self.splat_u32x4(32 - 1)))
1926 }
1927
1928 #[inline(always)]
1929 fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1930 self.shr_dyn_u32x4(a, self.and_u32x4(amount, self.splat_u32x4(32 - 1)))
1931 }
1932
1933 #[inline(always)]
1934 fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
1935 self.sqrt_f32x4(a)
1936 }
1937
1938 #[inline(always)]
1939 fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
1940 self.sqrt_f64x2(a)
1941 }
1942}
1943
1944impl Simd for V3_256b {
1945 type c32s = f32x8;
1946 type c64s = f64x4;
1947 type f32s = f32x8;
1948 type f64s = f64x4;
1949 type i16s = i16x16;
1950 type i32s = i32x8;
1951 type i64s = i64x4;
1952 type i8s = i8x32;
1953 type m16s = m16x16;
1954 type m32s = m32x8;
1955 type m64s = m64x4;
1956 type m8s = m8x32;
1957 type u16s = u16x16;
1958 type u32s = u32x8;
1959 type u64s = u64x4;
1960 type u8s = u8x32;
1961
1962 const REGISTER_COUNT: usize = 16;
1963
1964 impl_simd_binop!(add, f32 x 8, f64 x 4);
1965
1966 impl_simd_binop!(add, wrapping_add, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
1967
1968 impl_simd_binop!(sub, f32 x 8, f64 x 4);
1969
1970 impl_simd_binop!(sub, wrapping_sub, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
1971
1972 impl_simd_binop!(mul, f32 x 8, f64 x 4);
1973
1974 impl_simd_binop!(mul, wrapping_mul, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
1975
1976 impl_simd_binop!(and, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
1977
1978 impl_simd_binop!(or, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
1979
1980 impl_simd_binop!(xor, m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
1981
1982 impl_simd_binop!(div, f32 x 8, f64 x 4);
1983
1984 impl_simd_binop!(equal, cmp_eq, u8 x 32 => m8, u16 x 16 => m16, u32 x 8 => m32, u64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
1985
1986 impl_simd_binop!(greater_than, cmp_gt, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
1987
1988 impl_simd_binop!(greater_than_or_equal, cmp_ge, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
1989
1990 impl_simd_binop!(less_than, cmp_lt, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
1991
1992 impl_simd_binop!(less_than_or_equal, cmp_le, u8 x 32 => m8, i8 x 32 => m8, u16 x 16 => m16, i16 x 16 => m16, u32 x 8 => m32, i32 x 8 => m32, u64 x 4 => m64, i64 x 4 => m64, f32 x 8 => m32, f64 x 4 => m64);
1993
1994 splat!(u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4, f32 x 8, f64 x 4);
1995
1996 impl_simd_binop!(max, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, f32 x 8, f64 x 4);
1997
1998 impl_simd_binop!(min, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, f32 x 8, f64 x 4);
1999
2000 impl_simd_unop!(not, m8 x 32, u8 x 32, m16 x 16, u16 x 16, m32 x 8, u32 x 8, m64 x 4, u64 x 4);
2001
2002 inherit!({
2003 fn abs2_c32s(self, a: Self::c32s) -> Self::c32s;
2004 fn abs2_c64s(self, a: Self::c64s) -> Self::c64s;
2005 fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s;
2006 fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s;
2007 fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2008 fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2009 fn conj_c32s(self, a: Self::c32s) -> Self::c32s;
2010 fn conj_c64s(self, a: Self::c64s) -> Self::c64s;
2011 fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
2012 fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
2013 fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2014 fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2015 fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s;
2016 fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s;
2017 fn mask_between_m32s(self, start: u32, end: u32) -> MemMask<Self::m32s>;
2018 fn mask_between_m64s(self, start: u64, end: u64) -> MemMask<Self::m64s>;
2019 unsafe fn mask_load_ptr_c32s(
2023 self,
2024 mask: MemMask<Self::m32s>,
2025 ptr: *const c32,
2026 ) -> Self::c32s;
2027 unsafe fn mask_load_ptr_c64s(
2031 self,
2032 mask: MemMask<Self::m64s>,
2033 ptr: *const c64,
2034 ) -> Self::c64s;
2035 unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s;
2039 unsafe fn mask_load_ptr_u16s(
2043 self,
2044 mask: MemMask<Self::m16s>,
2045 ptr: *const u16,
2046 ) -> Self::u16s;
2047 unsafe fn mask_load_ptr_u32s(
2051 self,
2052 mask: MemMask<Self::m32s>,
2053 ptr: *const u32,
2054 ) -> Self::u32s;
2055 unsafe fn mask_load_ptr_u64s(
2059 self,
2060 mask: MemMask<Self::m64s>,
2061 ptr: *const u64,
2062 ) -> Self::u64s;
2063 unsafe fn mask_store_ptr_c32s(
2067 self,
2068 mask: MemMask<Self::m32s>,
2069 ptr: *mut c32,
2070 values: Self::c32s,
2071 );
2072 unsafe fn mask_store_ptr_c64s(
2076 self,
2077 mask: MemMask<Self::m64s>,
2078 ptr: *mut c64,
2079 values: Self::c64s,
2080 );
2081 unsafe fn mask_store_ptr_u8s(
2085 self,
2086 mask: MemMask<Self::m8s>,
2087 ptr: *mut u8,
2088 values: Self::u8s,
2089 );
2090 unsafe fn mask_store_ptr_u16s(
2094 self,
2095 mask: MemMask<Self::m16s>,
2096 ptr: *mut u16,
2097 values: Self::u16s,
2098 );
2099 unsafe fn mask_store_ptr_u32s(
2103 self,
2104 mask: MemMask<Self::m32s>,
2105 ptr: *mut u32,
2106 values: Self::u32s,
2107 );
2108 unsafe fn mask_store_ptr_u64s(
2112 self,
2113 mask: MemMask<Self::m64s>,
2114 ptr: *mut u64,
2115 values: Self::u64s,
2116 );
2117 fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
2118 fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
2119 fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2120 fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2121 fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2122 fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2123 fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2124 fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2125 fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2126 fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2127 fn mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2128 fn mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2129 fn neg_c32s(self, a: Self::c32s) -> Self::c32s;
2130 fn neg_c64s(self, a: Self::c64s) -> Self::c64s;
2131 fn min_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2132 fn min_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s;
2133 fn max_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2134 fn max_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s;
2135 fn mul_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2136 fn mul_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s;
2137 fn partial_load_u32s(self, slice: &[u32]) -> Self::u32s;
2138 fn partial_load_u64s(self, slice: &[u64]) -> Self::u64s;
2139 fn partial_store_u32s(self, slice: &mut [u32], values: Self::u32s);
2140 fn partial_store_u64s(self, slice: &mut [u64], values: Self::u64s);
2141 fn reduce_max_c32s(self, a: Self::c32s) -> c32;
2142 fn reduce_max_c64s(self, a: Self::c64s) -> c64;
2143 fn reduce_max_f32s(self, a: Self::f32s) -> f32;
2144 fn reduce_max_f64s(self, a: Self::f64s) -> f64;
2145 fn reduce_min_c32s(self, a: Self::c32s) -> c32;
2146 fn reduce_min_c64s(self, a: Self::c64s) -> c64;
2147 fn reduce_min_f32s(self, a: Self::f32s) -> f32;
2148 fn reduce_min_f64s(self, a: Self::f64s) -> f64;
2149 fn reduce_product_f32s(self, a: Self::f32s) -> f32;
2150 fn reduce_product_f64s(self, a: Self::f64s) -> f64;
2151 fn reduce_sum_c32s(self, a: Self::c32s) -> c32;
2152 fn reduce_sum_c64s(self, a: Self::c64s) -> c64;
2153 fn reduce_sum_f32s(self, a: Self::f32s) -> f32;
2154 fn reduce_sum_f64s(self, a: Self::f64s) -> f64;
2155 fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s;
2156 fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s;
2157 fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s;
2158 fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s;
2159 fn select_u32s(
2160 self,
2161 mask: Self::m32s,
2162 if_true: Self::u32s,
2163 if_false: Self::u32s,
2164 ) -> Self::u32s;
2165 fn select_u64s(
2166 self,
2167 mask: Self::m64s,
2168 if_true: Self::u64s,
2169 if_false: Self::u64s,
2170 ) -> Self::u64s;
2171 fn splat_c32s(self, a: c32) -> Self::c32s;
2172 fn splat_c64s(self, a: c64) -> Self::c64s;
2173 fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2174 fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2175 fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s;
2176 fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s;
2177 fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s);
2178 fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
2179 fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
2180 });
2181
2182 #[inline(always)]
2183 fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
2184 Simd::vectorize(self.0, op)
2185 }
2186
2187 #[inline(always)]
2188 fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
2189 self.sqrt_f32x8(a)
2190 }
2191
2192 #[inline(always)]
2193 fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
2194 self.sqrt_f64x4(a)
2195 }
2196}
2197
2198impl Simd for V3_512b {
2199 type c32s = f32x16;
2200 type c64s = f64x8;
2201 type f32s = f32x16;
2202 type f64s = f64x8;
2203 type i16s = i16x32;
2204 type i32s = i32x16;
2205 type i64s = i64x8;
2206 type i8s = i8x64;
2207 type m16s = m16x32;
2208 type m32s = m32x16;
2209 type m64s = m64x8;
2210 type m8s = m8x64;
2211 type u16s = u16x32;
2212 type u32s = u32x16;
2213 type u64s = u64x8;
2214 type u8s = u8x64;
2215
2216 const REGISTER_COUNT: usize = 8;
2217
2218 inherit_x2!(V3_256b(*self), {
2219 fn abs2_c32s(self, a: Self::c32s) -> Self::c32s;
2220 fn abs2_c64s(self, a: Self::c64s) -> Self::c64s;
2221 fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s;
2222 fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s;
2223 fn add_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2224 fn add_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2225 fn add_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2226 fn add_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2227 fn add_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2228 fn add_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2229 fn add_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2230 fn add_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2231 fn and_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s;
2232 fn and_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s;
2233 fn and_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2234 fn and_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2235 fn and_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2236 fn and_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2237 fn and_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2238 fn and_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2239 fn conj_c32s(self, a: Self::c32s) -> Self::c32s;
2240 fn conj_c64s(self, a: Self::c64s) -> Self::c64s;
2241 fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
2242 fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
2243 fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2244 fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2245 fn div_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2246 fn div_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2247 fn equal_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::m32s;
2248 fn equal_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::m64s;
2249 fn equal_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::m32s;
2250 fn equal_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::m64s;
2251 fn equal_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::m8s;
2252 fn equal_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::m8s;
2253 fn equal_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::m16s;
2254 fn equal_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::m16s;
2255 fn equal_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::m32s;
2256 fn equal_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::m32s;
2257 fn equal_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::m64s;
2258 fn equal_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::m64s;
2259 fn greater_than_or_equal_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::m8s;
2260 fn greater_than_or_equal_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::m8s;
2261 fn greater_than_or_equal_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::m16s;
2262 fn greater_than_or_equal_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::m16s;
2263 fn greater_than_or_equal_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::m32s;
2264 fn greater_than_or_equal_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::m32s;
2265 fn greater_than_or_equal_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::m64s;
2266 fn greater_than_or_equal_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::m64s;
2267 fn greater_than_or_equal_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::m32s;
2268 fn greater_than_or_equal_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::m64s;
2269 fn greater_than_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::m8s;
2270 fn greater_than_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::m8s;
2271 fn greater_than_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::m16s;
2272 fn greater_than_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::m16s;
2273 fn greater_than_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::m32s;
2274 fn greater_than_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::m32s;
2275 fn greater_than_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::m64s;
2276 fn greater_than_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::m64s;
2277 fn greater_than_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::m32s;
2278 fn greater_than_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::m64s;
2279 fn less_than_or_equal_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::m8s;
2280 fn less_than_or_equal_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::m8s;
2281 fn less_than_or_equal_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::m16s;
2282 fn less_than_or_equal_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::m16s;
2283 fn less_than_or_equal_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::m32s;
2284 fn less_than_or_equal_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::m32s;
2285 fn less_than_or_equal_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::m64s;
2286 fn less_than_or_equal_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::m64s;
2287 fn less_than_or_equal_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::m32s;
2288 fn less_than_or_equal_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::m64s;
2289 fn less_than_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::m8s;
2290 fn less_than_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::m8s;
2291 fn less_than_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::m16s;
2292 fn less_than_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::m16s;
2293 fn less_than_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::m32s;
2294 fn less_than_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::m32s;
2295 fn less_than_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::m64s;
2296 fn less_than_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::m64s;
2297 fn less_than_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::m32s;
2298 fn less_than_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::m64s;
2299 fn min_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2300 fn max_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2301 fn min_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::i8s;
2302 fn max_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::i8s;
2303 fn min_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2304 fn max_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2305 fn min_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::i16s;
2306 fn max_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::i16s;
2307 fn min_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2308 fn max_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2309 fn min_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::i32s;
2310 fn max_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::i32s;
2311 fn max_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2312 fn max_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2313 fn min_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2314 fn min_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2315 fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
2316 fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
2317 fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2318 fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2319 fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2320 fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2321 fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2322 fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2323 fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
2324 fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
2325 fn mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2326 fn mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2327 fn mul_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2328 fn mul_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2329 fn mul_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2330 fn mul_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::i16s;
2331 fn mul_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2332 fn mul_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::i32s;
2333 fn mul_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2334 fn mul_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s;
2335 fn neg_c32s(self, a: Self::c32s) -> Self::c32s;
2336 fn neg_c64s(self, a: Self::c64s) -> Self::c64s;
2337 fn not_m8s(self, a: Self::m8s) -> Self::m8s;
2338 fn not_m16s(self, a: Self::m16s) -> Self::m16s;
2339 fn not_m32s(self, a: Self::m32s) -> Self::m32s;
2340 fn not_m64s(self, a: Self::m64s) -> Self::m64s;
2341 fn not_f32s(self, a: Self::f32s) -> Self::f32s;
2342 fn not_f64s(self, a: Self::f64s) -> Self::f64s;
2343 fn not_u8s(self, a: Self::u8s) -> Self::u8s;
2344 fn not_u16s(self, a: Self::u16s) -> Self::u16s;
2345 fn not_u32s(self, a: Self::u32s) -> Self::u32s;
2346 fn not_u64s(self, a: Self::u64s) -> Self::u64s;
2347 fn or_m8s(self, a: Self::m8s, b: Self::m8s) -> Self::m8s;
2348 fn or_m16s(self, a: Self::m16s, b: Self::m16s) -> Self::m16s;
2349 fn or_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s;
2350 fn or_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s;
2351 fn or_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2352 fn or_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2353 fn or_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2354 fn or_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2355 fn or_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2356 fn or_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2357 fn select_u32s(
2358 self,
2359 mask: Self::m32s,
2360 if_true: Self::u32s,
2361 if_false: Self::u32s,
2362 ) -> Self::u32s;
2363 fn select_u64s(
2364 self,
2365 mask: Self::m64s,
2366 if_true: Self::u64s,
2367 if_false: Self::u64s,
2368 ) -> Self::u64s;
2369 fn sub_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
2370 fn sub_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
2371 fn sub_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2372 fn sub_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2373 fn sub_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2374 fn sub_i8s(self, a: Self::i8s, b: Self::i8s) -> Self::i8s;
2375 fn sub_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2376 fn sub_i16s(self, a: Self::i16s, b: Self::i16s) -> Self::i16s;
2377 fn sub_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2378 fn sub_i32s(self, a: Self::i32s, b: Self::i32s) -> Self::i32s;
2379 fn sub_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2380 fn sub_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s;
2381 fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s;
2382 fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s;
2383 fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
2384 fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
2385 fn xor_m8s(self, a: Self::m8s, b: Self::m8s) -> Self::m8s;
2386 fn xor_m16s(self, a: Self::m16s, b: Self::m16s) -> Self::m16s;
2387 fn xor_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s;
2388 fn xor_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s;
2389 fn xor_f32s(self, a: Self::f32s, b: Self::f32s) -> Self::f32s;
2390 fn xor_f64s(self, a: Self::f64s, b: Self::f64s) -> Self::f64s;
2391 fn xor_u8s(self, a: Self::u8s, b: Self::u8s) -> Self::u8s;
2392 fn xor_u16s(self, a: Self::u16s, b: Self::u16s) -> Self::u16s;
2393 fn xor_u32s(self, a: Self::u32s, b: Self::u32s) -> Self::u32s;
2394 fn xor_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s;
2395 });
2396
2397 inherit_x2!(V3_256b(*self), splat, {
2398 fn splat_c32s(self, value: c32) -> Self::c32s;
2399 fn splat_c64s(self, value: c64) -> Self::c64s;
2400 fn splat_f32s(self, value: f32) -> Self::f32s;
2401 fn splat_f64s(self, value: f64) -> Self::f64s;
2402 fn splat_u8s(self, value: u8) -> Self::u8s;
2403 fn splat_i8s(self, value: i8) -> Self::i8s;
2404 fn splat_u16s(self, value: u16) -> Self::u16s;
2405 fn splat_i16s(self, value: i16) -> Self::i16s;
2406 fn splat_u32s(self, value: u32) -> Self::u32s;
2407 fn splat_i32s(self, value: i32) -> Self::i32s;
2408 fn splat_u64s(self, value: u64) -> Self::u64s;
2409 fn splat_i64s(self, value: i64) -> Self::i64s;
2410 });
2411
2412 inherit_x2!(V3_256b(*self), wide, {
2413 fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s);
2414 });
2415
2416 #[inline(always)]
2417 fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
2418 let simd = V3_256b(*self);
2419 let amount = amount % Self::C32_LANES;
2420 let [mut a0, mut a1]: [_; 2] = cast!(a);
2421 if amount >= Self::C32_LANES / 2 {
2422 core::mem::swap(&mut a0, &mut a1);
2423 }
2424 let amount = amount % (Self::C32_LANES / 2);
2425 let mask = simd.mask_between_m32s(0, amount as _).mask();
2426 let a0 = simd.rotate_right_c32s(a0, amount);
2427 let a1 = simd.rotate_right_c32s(a1, amount);
2428
2429 cast!([
2430 simd.select_f32s(mask, a1, a0),
2431 simd.select_f32s(mask, a0, a1),
2432 ])
2433 }
2434
2435 #[inline(always)]
2436 fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
2437 let simd = V3_256b(*self);
2438 let amount = amount % Self::C64_LANES;
2439 let [mut a0, mut a1]: [_; 2] = cast!(a);
2440 if amount >= Self::C64_LANES / 2 {
2441 core::mem::swap(&mut a0, &mut a1);
2442 }
2443 let amount = amount % (Self::C64_LANES / 2);
2444 let mask = simd.mask_between_m64s(0, amount as _).mask();
2445 let a0 = simd.rotate_right_c64s(a0, amount);
2446 let a1 = simd.rotate_right_c64s(a1, amount);
2447
2448 cast!([
2449 simd.select_f64s(mask, a1, a0),
2450 simd.select_f64s(mask, a0, a1),
2451 ])
2452 }
2453
2454 #[inline(always)]
2455 fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
2456 let simd = V3_256b(*self);
2457 let amount = amount % Self::U32_LANES;
2458 let [mut a0, mut a1]: [_; 2] = cast!(a);
2459 if amount >= Self::U32_LANES / 2 {
2460 core::mem::swap(&mut a0, &mut a1);
2461 }
2462 let amount = amount % (Self::U32_LANES / 2);
2463 let mask = simd.mask_between_m32s(0, amount as _).mask();
2464 let a0 = simd.rotate_right_u32s(a0, amount);
2465 let a1 = simd.rotate_right_u32s(a1, amount);
2466
2467 cast!([
2468 simd.select_u32s(mask, a1, a0),
2469 simd.select_u32s(mask, a0, a1),
2470 ])
2471 }
2472
2473 #[inline(always)]
2474 fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
2475 let simd = V3_256b(*self);
2476 let amount = amount % Self::U64_LANES;
2477 let [mut a0, mut a1]: [_; 2] = cast!(a);
2478 if amount >= Self::U64_LANES / 2 {
2479 core::mem::swap(&mut a0, &mut a1);
2480 }
2481 let amount = amount % (Self::U64_LANES / 2);
2482 let mask = simd.mask_between_m64s(0, amount as _).mask();
2483 let a0 = simd.rotate_right_u64s(a0, amount);
2484 let a1 = simd.rotate_right_u64s(a1, amount);
2485
2486 cast!([
2487 simd.select_u64s(mask, a1, a0),
2488 simd.select_u64s(mask, a0, a1),
2489 ])
2490 }
2491
2492 #[inline(always)]
2496 unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
2497 let simd = V3_256b(*self);
2498 let mask: [_; 2] = cast!(mask.mask());
2499 cast!([
2500 simd.mask_load_ptr_c32s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2501 simd.mask_load_ptr_c32s(MemMask::new(mask[1]), ptr.wrapping_add(Self::C32_LANES)),
2502 ])
2503 }
2504
2505 #[inline(always)]
2509 unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
2510 let simd = V3_256b(*self);
2511 let mask: [_; 2] = cast!(mask.mask());
2512 cast!([
2513 simd.mask_load_ptr_c64s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2514 simd.mask_load_ptr_c64s(MemMask::new(mask[1]), ptr.wrapping_add(Self::C64_LANES)),
2515 ])
2516 }
2517
2518 #[inline(always)]
2522 unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
2523 let simd = V3_256b(*self);
2524 let mask: [_; 2] = cast!(mask.mask());
2525 cast!([
2526 simd.mask_load_ptr_u8s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2527 simd.mask_load_ptr_u8s(MemMask::new(mask[1]), ptr.wrapping_add(V3_256b::U8_LANES)),
2528 ])
2529 }
2530
2531 #[inline(always)]
2535 unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
2536 let simd = V3_256b(*self);
2537 let mask: [_; 2] = cast!(mask.mask());
2538 cast!([
2539 simd.mask_load_ptr_u16s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2540 simd.mask_load_ptr_u16s(MemMask::new(mask[1]), ptr.wrapping_add(V3_256b::U16_LANES)),
2541 ])
2542 }
2543
2544 #[inline(always)]
2548 unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
2549 let simd = V3_256b(*self);
2550 let mask: [_; 2] = cast!(mask.mask());
2551 cast!([
2552 simd.mask_load_ptr_u32s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2553 simd.mask_load_ptr_u32s(MemMask::new(mask[1]), ptr.wrapping_add(Self::U32_LANES)),
2554 ])
2555 }
2556
2557 #[inline(always)]
2561 unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
2562 let simd = V3_256b(*self);
2563 let mask: [_; 2] = cast!(mask.mask());
2564 cast!([
2565 simd.mask_load_ptr_u64s(MemMask::new(mask[0]), ptr.wrapping_add(0)),
2566 simd.mask_load_ptr_u64s(MemMask::new(mask[1]), ptr.wrapping_add(Self::U64_LANES)),
2567 ])
2568 }
2569
2570 #[inline(always)]
2574 unsafe fn mask_store_ptr_c32s(
2575 self,
2576 mask: MemMask<Self::m32s>,
2577 ptr: *mut c32,
2578 values: Self::c32s,
2579 ) {
2580 let simd = V3_256b(*self);
2581 let mask: [_; 2] = cast!(mask.mask());
2582 let values: [_; 2] = cast!(values);
2583 cast!([
2584 simd.mask_store_ptr_c32s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2585 simd.mask_store_ptr_c32s(
2586 MemMask::new(mask[1]),
2587 ptr.wrapping_add(Self::C32_LANES),
2588 values[1]
2589 ),
2590 ])
2591 }
2592
2593 #[inline(always)]
2597 unsafe fn mask_store_ptr_c64s(
2598 self,
2599 mask: MemMask<Self::m64s>,
2600 ptr: *mut c64,
2601 values: Self::c64s,
2602 ) {
2603 let simd = V3_256b(*self);
2604 let mask: [_; 2] = cast!(mask.mask());
2605 let values: [_; 2] = cast!(values);
2606 cast!([
2607 simd.mask_store_ptr_c64s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2608 simd.mask_store_ptr_c64s(
2609 MemMask::new(mask[1]),
2610 ptr.wrapping_add(Self::C64_LANES),
2611 values[1]
2612 ),
2613 ])
2614 }
2615
2616 #[inline(always)]
2620 unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
2621 let simd = V3_256b(*self);
2622 let mask: [_; 2] = cast!(mask.mask());
2623 let values: [_; 2] = cast!(values);
2624 cast!([
2625 simd.mask_store_ptr_u8s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2626 simd.mask_store_ptr_u8s(
2627 MemMask::new(mask[1]),
2628 ptr.wrapping_add(V3_256b::U8_LANES),
2629 values[1]
2630 ),
2631 ])
2632 }
2633
2634 #[inline(always)]
2638 unsafe fn mask_store_ptr_u16s(
2639 self,
2640 mask: MemMask<Self::m16s>,
2641 ptr: *mut u16,
2642 values: Self::u16s,
2643 ) {
2644 let simd = V3_256b(*self);
2645 let mask: [_; 2] = cast!(mask.mask());
2646 let values: [_; 2] = cast!(values);
2647 cast!([
2648 simd.mask_store_ptr_u16s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2649 simd.mask_store_ptr_u16s(
2650 MemMask::new(mask[1]),
2651 ptr.wrapping_add(V3_256b::U16_LANES),
2652 values[1]
2653 ),
2654 ])
2655 }
2656
2657 #[inline(always)]
2661 unsafe fn mask_store_ptr_u32s(
2662 self,
2663 mask: MemMask<Self::m32s>,
2664 ptr: *mut u32,
2665 values: Self::u32s,
2666 ) {
2667 let simd = V3_256b(*self);
2668 let mask: [_; 2] = cast!(mask.mask());
2669 let values: [_; 2] = cast!(values);
2670 cast!([
2671 simd.mask_store_ptr_u32s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2672 simd.mask_store_ptr_u32s(
2673 MemMask::new(mask[1]),
2674 ptr.wrapping_add(Self::U32_LANES),
2675 values[1]
2676 ),
2677 ])
2678 }
2679
2680 #[inline(always)]
2684 unsafe fn mask_store_ptr_u64s(
2685 self,
2686 mask: MemMask<Self::m64s>,
2687 ptr: *mut u64,
2688 values: Self::u64s,
2689 ) {
2690 let simd = V3_256b(*self);
2691 let mask: [_; 2] = cast!(mask.mask());
2692 let values: [_; 2] = cast!(values);
2693 cast!([
2694 simd.mask_store_ptr_u64s(MemMask::new(mask[0]), ptr.wrapping_add(0), values[0]),
2695 simd.mask_store_ptr_u64s(
2696 MemMask::new(mask[1]),
2697 ptr.wrapping_add(Self::U64_LANES),
2698 values[1]
2699 ),
2700 ])
2701 }
2702
2703 #[inline(always)]
2704 fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
2705 let simd = V3_256b(*self);
2706 let a: [_; 2] = cast!(a);
2707 simd.reduce_max_c32s(simd.max_f32s(a[0], a[1]))
2708 }
2709
2710 #[inline(always)]
2711 fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
2712 let simd = V3_256b(*self);
2713 let a: [_; 2] = cast!(a);
2714 simd.reduce_max_c64s(simd.max_f64s(a[0], a[1]))
2715 }
2716
2717 #[inline(always)]
2718 fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
2719 let simd = V3_256b(*self);
2720 let a: [_; 2] = cast!(a);
2721 simd.reduce_max_f32s(simd.max_f32s(a[0], a[1]))
2722 }
2723
2724 #[inline(always)]
2725 fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
2726 let simd = V3_256b(*self);
2727 let a: [_; 2] = cast!(a);
2728 simd.reduce_max_f64s(simd.max_f64s(a[0], a[1]))
2729 }
2730
2731 #[inline(always)]
2732 fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
2733 let simd = V3_256b(*self);
2734 let a: [_; 2] = cast!(a);
2735 simd.reduce_min_c32s(simd.min_f32s(a[0], a[1]))
2736 }
2737
2738 #[inline(always)]
2739 fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
2740 let simd = V3_256b(*self);
2741 let a: [_; 2] = cast!(a);
2742 simd.reduce_min_c64s(simd.min_f64s(a[0], a[1]))
2743 }
2744
2745 #[inline(always)]
2746 fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
2747 let simd = V3_256b(*self);
2748 let a: [_; 2] = cast!(a);
2749 simd.reduce_min_f32s(simd.min_f32s(a[0], a[1]))
2750 }
2751
2752 #[inline(always)]
2753 fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
2754 let simd = V3_256b(*self);
2755 let a: [_; 2] = cast!(a);
2756 simd.reduce_min_f64s(simd.min_f64s(a[0], a[1]))
2757 }
2758
2759 #[inline(always)]
2760 fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
2761 let simd = V3_256b(*self);
2762 let a: [_; 2] = cast!(a);
2763 simd.reduce_product_f32s(simd.mul_f32s(a[0], a[1]))
2764 }
2765
2766 #[inline(always)]
2767 fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
2768 let simd = V3_256b(*self);
2769 let a: [_; 2] = cast!(a);
2770 simd.reduce_product_f64s(simd.mul_f64s(a[0], a[1]))
2771 }
2772
2773 #[inline(always)]
2774 fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
2775 let simd = V3_256b(*self);
2776 let a: [_; 2] = cast!(a);
2777 simd.reduce_sum_c32s(simd.add_c32s(a[0], a[1]))
2778 }
2779
2780 #[inline(always)]
2781 fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
2782 let simd = V3_256b(*self);
2783 let a: [_; 2] = cast!(a);
2784 simd.reduce_sum_c64s(simd.add_c64s(a[0], a[1]))
2785 }
2786
2787 #[inline(always)]
2788 fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
2789 let simd = V3_256b(*self);
2790 let a: [_; 2] = cast!(a);
2791 simd.reduce_sum_f32s(simd.add_f32s(a[0], a[1]))
2792 }
2793
2794 #[inline(always)]
2795 fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
2796 let simd = V3_256b(*self);
2797 let a: [_; 2] = cast!(a);
2798 simd.reduce_sum_f64s(simd.add_f64s(a[0], a[1]))
2799 }
2800
2801 #[inline(always)]
2802 fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
2803 Simd::vectorize(self.0, op)
2804 }
2805
2806 #[inline(always)]
2807 fn max_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s {
2808 Scalar512b.max_u64s(a, b)
2809 }
2810
2811 #[inline(always)]
2812 fn max_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s {
2813 Scalar512b.max_i64s(a, b)
2814 }
2815
2816 #[inline(always)]
2817 fn min_u64s(self, a: Self::u64s, b: Self::u64s) -> Self::u64s {
2818 Scalar512b.min_u64s(a, b)
2819 }
2820
2821 #[inline(always)]
2822 fn min_i64s(self, a: Self::i64s, b: Self::i64s) -> Self::i64s {
2823 Scalar512b.max_i64s(a, b)
2824 }
2825
2826 #[inline(always)]
2827 fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
2828 let a: [_; 2] = cast!(a);
2829 cast!([self.sqrt_f32x8(a[0]), self.sqrt_f32x8(a[1]),])
2830 }
2831
2832 #[inline(always)]
2833 fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
2834 let a: [_; 2] = cast!(a);
2835 cast!([self.sqrt_f64x4(a[0]), self.sqrt_f64x4(a[1]),])
2836 }
2837}
2838
2839impl V3 {
2840 binop_256_nosign!(avx: add, "Adds the elements of each lane of `a` and `b`.", f32 x 8, f64 x 4);
2841
2842 binop_256_nosign!(avx2: add, "Adds the elements of each lane of `a` and `b`, with wrapping on overflow.", wrapping_add, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
2843
2844 binop_256!(avx: and, "Returns `a & b` for each bit in `a` and `b`.", f32 x 8, f64 x 4);
2845
2846 binop_256_full!(avx2: and, "Returns `a & b` for each bit in `a` and `b`.", m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4);
2847
2848 binop_256!(avx: andnot, "Returns `!a & b` for each bit in `a` and `b`.", f32 x 8, f64 x 4);
2849
2850 binop_256_full!(avx2: andnot, "Returns `!a & b` for each bit in `a` and `b`.", m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4);
2851
2852 binop_256!(avx2: sign, r#"Applies the sign of each element of `sign` to the corresponding lane in `a`.
2853- If `sign` is zero, the corresponding element is zeroed.
2854- If `sign` is positive, the corresponding element is returned as is.
2855- If `sign` is negative, the corresponding element is negated."#, apply_sign, i8 x 32, i16 x 16, i32 x 8);
2856
2857 binop_256!(avx2: avg, "Computes `average(a, b)` for each lane of `a` and `b`.", average, u8 x 32, u16 x 16);
2858
2859 unop_256!(avx: ceil, "Returns `ceil(a)` for each lane of `a`, rounding towards positive infinity.", f32 x 8, f64 x 4);
2860
2861 binop_256_nosign!(avx2: cmpeq, "Compares the elements in each lane of `a` and `b` for equality.", cmp_eq, m8 x 32 => m8, u8 x 32 => m8, i8 x 32 => m8, m16 x 16 => m16, u16 x 16 => m16, i16 x 16 => m16, m32 x 8 => m32, u32 x 8 => m32, i32 x 8 => m32, m64 x 4 => m64, u64 x 4 => m64, i64 x 4 => m64);
2862
2863 binop_256!(avx2: cmpgt, "Compares the elements in each lane of `a` and `b` for equality.", cmp_gt, i8 x 32 => m8, i16 x 16 => m16, i32 x 8 => m32, i64 x 4 => m64);
2864
2865 binop_256!(avx: div, "Divides the elements of each lane of `a` and `b`.", f32 x 8, f64 x 4);
2866
2867 unop_256!(avx: floor, "Rounds the elements of each lane of `a` to the nearest integer towards negative infinity.", f32 x 8, f64 x 4);
2868
2869 binop_256_nosign!(avx: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, f32 x 8, f64 x 4);
2870
2871 binop_256_nosign!(avx2: hadd, "[_mm_hadd_ps](core::arch::x86_64::_mm_hadd_ps)", horizontal_add_pack, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
2872
2873 binop_256_nosign!(avx: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, f32 x 8, f64 x 4);
2874
2875 binop_256_nosign!(avx2: hsub, "[_mm_hsub_ps](core::arch::x86_64::_mm_hsub_ps)", horizontal_sub_pack, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
2876
2877 binop_256!(avx: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", f32 x 8, f64 x 4);
2878
2879 binop_256!(avx2: max, "Computes `max(a, b)`. for each lane in `a` and `b`.", u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
2880
2881 binop_256!(avx: min, "Computes `min(a, b)`. for each lane in `a` and `b`.", f32 x 8, f64 x 4);
2882
2883 binop_256!(avx2: min, "Computes `min(a, b)`. for each lane in `a` and `b`.", u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
2884
2885 binop_256!(avx: mul, "Computes `a * b` for each lane in `a` and `b`.", f32 x 8, f64 x 4);
2886
2887 binop_256_nosign!(avx2: mullo, "Computes `a * b` for each lane in `a` and `b`, with wrapping overflow.", wrapping_mul, u16 x 16, i16 x 16, u32 x 8, i32 x 8);
2888
2889 binop_256!(avx: or, "Returns `a | b` for each bit in `a` and `b`.", f32 x 8, f64 x 4);
2890
2891 binop_256_full!(avx2: or, "Returns `a | b` for each bit in `a` and `b`.", m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4);
2892
2893 binop_256!(avx2: adds, "Adds the elements of each lane of `a` and `b`, with saturation.", saturating_add, u8 x 32, i8 x 32, u16 x 16, i16 x 16);
2894
2895 binop_256!(avx2: subs, "Subtracts the elements of each lane of `a` and `b`, with saturation.", saturating_sub, u8 x 32, i8 x 32, u16 x 16, i16 x 16);
2896
2897 binop_256_nosign!(avx: sub, "Subtracts the elements of each lane of `a` and `b`.", f32 x 8, f64 x 4);
2898
2899 binop_256_nosign!(avx2: sub, "Subtracts the elements of each lane of `a` and `b`, with wrapping overflow.", wrapping_sub, u8 x 32, i8 x 32, u16 x 16, i16 x 16, u32 x 8, i32 x 8, u64 x 4, i64 x 4);
2900
2901 binop_256!(avx: addsub, "Alternatively subtracts and adds the elements of each lane of `a` and `b`.", subadd, f32 x 8, f64 x 4);
2902
2903 unop_256!(avx2: abs, "Computes the unsigned absolute value of the elements of each lane of `a`.", unsigned_abs, i8 x 32, i16 x 16, i32 x 8);
2904
2905 binop_256!(avx: xor, "Returns `a ^ b` for each bit in `a` and `b`.", f32 x 8, f64 x 4);
2906
2907 binop_256_full!(avx2: xor, "Returns `a ^ b` for each bit in `a` and `b`.", m8 x 32, u8 x 32, i8 x 32, m16 x 16, u16 x 16, i16 x 16, m32 x 8, u32 x 8, i32 x 8, m64 x 4, u64 x 4, i64 x 4);
2908
2909 #[inline(always)]
2911 pub fn abs_f32x8(self, a: f32x8) -> f32x8 {
2912 self.and_f32x8(a, cast!(self.splat_u32x8((1 << 31) - 1)))
2913 }
2914
2915 #[inline(always)]
2917 pub fn abs_f64x4(self, a: f64x4) -> f64x4 {
2918 self.and_f64x4(a, cast!(self.splat_u64x4((1 << 63) - 1)))
2919 }
2920
2921 #[inline(always)]
2923 pub fn approx_reciprocal_f32x8(self, a: f32x8) -> f32x8 {
2924 cast!(self.avx._mm256_rcp_ps(cast!(a)))
2925 }
2926
2927 #[inline(always)]
2929 pub fn approx_reciprocal_sqrt_f32x8(self, a: f32x8) -> f32x8 {
2930 cast!(self.avx._mm256_rsqrt_ps(cast!(a)))
2931 }
2932
2933 #[inline(always)]
2935 pub fn cmp_eq_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
2936 cast!(self.avx._mm256_cmp_ps::<_CMP_EQ_OQ>(cast!(a), cast!(b)))
2937 }
2938
2939 #[inline(always)]
2941 pub fn cmp_eq_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
2942 cast!(self.avx._mm256_cmp_pd::<_CMP_EQ_OQ>(cast!(a), cast!(b)))
2943 }
2944
2945 #[inline(always)]
2947 pub fn cmp_ge_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
2948 cast!(self.avx._mm256_cmp_ps::<_CMP_GE_OQ>(cast!(a), cast!(b)))
2949 }
2950
2951 #[inline(always)]
2953 pub fn cmp_ge_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
2954 cast!(self.avx._mm256_cmp_pd::<_CMP_GE_OQ>(cast!(a), cast!(b)))
2955 }
2956
2957 #[inline(always)]
2959 pub fn cmp_ge_i16x16(self, a: i16x16, b: i16x16) -> m16x16 {
2960 self.not_m16x16(self.cmp_lt_i16x16(a, b))
2961 }
2962
2963 #[inline(always)]
2965 pub fn cmp_ge_i32x8(self, a: i32x8, b: i32x8) -> m32x8 {
2966 self.not_m32x8(self.cmp_lt_i32x8(a, b))
2967 }
2968
2969 #[inline(always)]
2971 pub fn cmp_ge_i64x4(self, a: i64x4, b: i64x4) -> m64x4 {
2972 self.not_m64x4(self.cmp_lt_i64x4(a, b))
2973 }
2974
2975 #[inline(always)]
2977 pub fn cmp_ge_i8x32(self, a: i8x32, b: i8x32) -> m8x32 {
2978 self.not_m8x32(self.cmp_lt_i8x32(a, b))
2979 }
2980
2981 #[inline(always)]
2983 pub fn cmp_ge_u16x16(self, a: u16x16, b: u16x16) -> m16x16 {
2984 self.not_m16x16(self.cmp_lt_u16x16(a, b))
2985 }
2986
2987 #[inline(always)]
2989 pub fn cmp_ge_u32x8(self, a: u32x8, b: u32x8) -> m32x8 {
2990 self.not_m32x8(self.cmp_lt_u32x8(a, b))
2991 }
2992
2993 #[inline(always)]
2995 pub fn cmp_ge_u64x4(self, a: u64x4, b: u64x4) -> m64x4 {
2996 self.not_m64x4(self.cmp_lt_u64x4(a, b))
2997 }
2998
2999 #[inline(always)]
3001 pub fn cmp_ge_u8x32(self, a: u8x32, b: u8x32) -> m8x32 {
3002 self.not_m8x32(self.cmp_lt_u8x32(a, b))
3003 }
3004
3005 #[inline(always)]
3007 pub fn cmp_gt_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3008 cast!(self.avx._mm256_cmp_ps::<_CMP_GT_OQ>(cast!(a), cast!(b)))
3009 }
3010
3011 #[inline(always)]
3013 pub fn cmp_gt_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3014 cast!(self.avx._mm256_cmp_pd::<_CMP_GT_OQ>(cast!(a), cast!(b)))
3015 }
3016
3017 #[inline(always)]
3019 pub fn cmp_gt_u16x16(self, a: u16x16, b: u16x16) -> m16x16 {
3020 let k = self.splat_u16x16(0x8000);
3021 self.cmp_gt_i16x16(cast!(self.xor_u16x16(a, k)), cast!(self.xor_u16x16(b, k)))
3022 }
3023
3024 #[inline(always)]
3026 pub fn cmp_gt_u32x8(self, a: u32x8, b: u32x8) -> m32x8 {
3027 let k = self.splat_u32x8(0x80000000);
3028 self.cmp_gt_i32x8(cast!(self.xor_u32x8(a, k)), cast!(self.xor_u32x8(b, k)))
3029 }
3030
3031 #[inline(always)]
3033 pub fn cmp_gt_u64x4(self, a: u64x4, b: u64x4) -> m64x4 {
3034 let k = self.splat_u64x4(0x8000000000000000);
3035 self.cmp_gt_i64x4(cast!(self.xor_u64x4(a, k)), cast!(self.xor_u64x4(b, k)))
3036 }
3037
3038 #[inline(always)]
3040 pub fn cmp_gt_u8x32(self, a: u8x32, b: u8x32) -> m8x32 {
3041 let k = self.splat_u8x32(0x80);
3042 self.cmp_gt_i8x32(cast!(self.xor_u8x32(a, k)), cast!(self.xor_u8x32(b, k)))
3043 }
3044
3045 #[inline(always)]
3047 pub fn cmp_le_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3048 cast!(self.avx._mm256_cmp_ps::<_CMP_LE_OQ>(cast!(a), cast!(b)))
3049 }
3050
3051 #[inline(always)]
3053 pub fn cmp_le_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3054 cast!(self.avx._mm256_cmp_pd::<_CMP_LE_OQ>(cast!(a), cast!(b)))
3055 }
3056
3057 #[inline(always)]
3059 pub fn cmp_le_i16x16(self, a: i16x16, b: i16x16) -> m16x16 {
3060 self.not_m16x16(self.cmp_gt_i16x16(a, b))
3061 }
3062
3063 #[inline(always)]
3065 pub fn cmp_le_i32x8(self, a: i32x8, b: i32x8) -> m32x8 {
3066 self.not_m32x8(self.cmp_gt_i32x8(a, b))
3067 }
3068
3069 #[inline(always)]
3071 pub fn cmp_le_i64x4(self, a: i64x4, b: i64x4) -> m64x4 {
3072 self.not_m64x4(self.cmp_gt_i64x4(a, b))
3073 }
3074
3075 #[inline(always)]
3077 pub fn cmp_le_i8x32(self, a: i8x32, b: i8x32) -> m8x32 {
3078 self.not_m8x32(self.cmp_gt_i8x32(a, b))
3079 }
3080
3081 #[inline(always)]
3083 pub fn cmp_le_u16x16(self, a: u16x16, b: u16x16) -> m16x16 {
3084 self.not_m16x16(self.cmp_gt_u16x16(a, b))
3085 }
3086
3087 #[inline(always)]
3089 pub fn cmp_le_u32x8(self, a: u32x8, b: u32x8) -> m32x8 {
3090 self.not_m32x8(self.cmp_gt_u32x8(a, b))
3091 }
3092
3093 #[inline(always)]
3095 pub fn cmp_le_u64x4(self, a: u64x4, b: u64x4) -> m64x4 {
3096 self.not_m64x4(self.cmp_gt_u64x4(a, b))
3097 }
3098
3099 #[inline(always)]
3101 pub fn cmp_le_u8x32(self, a: u8x32, b: u8x32) -> m8x32 {
3102 self.not_m8x32(self.cmp_gt_u8x32(a, b))
3103 }
3104
3105 #[inline(always)]
3107 pub fn cmp_lt_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3108 cast!(self.avx._mm256_cmp_ps::<_CMP_LT_OQ>(cast!(a), cast!(b)))
3109 }
3110
3111 #[inline(always)]
3113 pub fn cmp_lt_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3114 cast!(self.avx._mm256_cmp_pd::<_CMP_LT_OQ>(cast!(a), cast!(b)))
3115 }
3116
3117 #[inline(always)]
3119 pub fn cmp_lt_i16x16(self, a: i16x16, b: i16x16) -> m16x16 {
3120 cast!(self.avx2._mm256_cmpgt_epi16(cast!(b), cast!(a)))
3121 }
3122
3123 #[inline(always)]
3125 pub fn cmp_lt_i32x8(self, a: i32x8, b: i32x8) -> m32x8 {
3126 cast!(self.avx2._mm256_cmpgt_epi32(cast!(b), cast!(a)))
3127 }
3128
3129 #[inline(always)]
3131 pub fn cmp_lt_i64x4(self, a: i64x4, b: i64x4) -> m64x4 {
3132 cast!(self.avx2._mm256_cmpgt_epi64(cast!(b), cast!(a)))
3133 }
3134
3135 #[inline(always)]
3137 pub fn cmp_lt_i8x32(self, a: i8x32, b: i8x32) -> m8x32 {
3138 cast!(self.avx2._mm256_cmpgt_epi8(cast!(b), cast!(a)))
3139 }
3140
3141 #[inline(always)]
3143 pub fn cmp_lt_u16x16(self, a: u16x16, b: u16x16) -> m16x16 {
3144 let k = self.splat_u16x16(0x8000);
3145 self.cmp_lt_i16x16(cast!(self.xor_u16x16(a, k)), cast!(self.xor_u16x16(b, k)))
3146 }
3147
3148 #[inline(always)]
3150 pub fn cmp_lt_u32x8(self, a: u32x8, b: u32x8) -> m32x8 {
3151 let k = self.splat_u32x8(0x80000000);
3152 self.cmp_lt_i32x8(cast!(self.xor_u32x8(a, k)), cast!(self.xor_u32x8(b, k)))
3153 }
3154
3155 #[inline(always)]
3157 pub fn cmp_lt_u64x4(self, a: u64x4, b: u64x4) -> m64x4 {
3158 let k = self.splat_u64x4(0x8000000000000000);
3159 self.cmp_lt_i64x4(cast!(self.xor_u64x4(a, k)), cast!(self.xor_u64x4(b, k)))
3160 }
3161
3162 #[inline(always)]
3164 pub fn cmp_lt_u8x32(self, a: u8x32, b: u8x32) -> m8x32 {
3165 let k = self.splat_u8x32(0x80);
3166 self.cmp_lt_i8x32(cast!(self.xor_u8x32(a, k)), cast!(self.xor_u8x32(b, k)))
3167 }
3168
3169 #[inline(always)]
3171 pub fn cmp_not_eq_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3172 cast!(self.avx._mm256_cmp_ps::<_CMP_NEQ_UQ>(cast!(a), cast!(b)))
3173 }
3174
3175 #[inline(always)]
3177 pub fn cmp_not_eq_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3178 cast!(self.avx._mm256_cmp_pd::<_CMP_NEQ_UQ>(cast!(a), cast!(b)))
3179 }
3180
3181 #[inline(always)]
3183 pub fn cmp_not_ge_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3184 cast!(self.avx._mm256_cmp_ps::<_CMP_NGE_UQ>(cast!(a), cast!(b)))
3185 }
3186
3187 #[inline(always)]
3189 pub fn cmp_not_ge_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3190 cast!(self.avx._mm256_cmp_pd::<_CMP_NGE_UQ>(cast!(a), cast!(b)))
3191 }
3192
3193 #[inline(always)]
3195 pub fn cmp_not_gt_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3196 cast!(self.avx._mm256_cmp_ps::<_CMP_NGT_UQ>(cast!(a), cast!(b)))
3197 }
3198
3199 #[inline(always)]
3201 pub fn cmp_not_gt_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3202 cast!(self.avx._mm256_cmp_pd::<_CMP_NGT_UQ>(cast!(a), cast!(b)))
3203 }
3204
3205 #[inline(always)]
3207 pub fn cmp_not_le_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3208 cast!(self.avx._mm256_cmp_ps::<_CMP_NLE_UQ>(cast!(a), cast!(b)))
3209 }
3210
3211 #[inline(always)]
3213 pub fn cmp_not_le_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3214 cast!(self.avx._mm256_cmp_pd::<_CMP_NLE_UQ>(cast!(a), cast!(b)))
3215 }
3216
3217 #[inline(always)]
3219 pub fn cmp_not_lt_f32x8(self, a: f32x8, b: f32x8) -> m32x8 {
3220 cast!(self.avx._mm256_cmp_ps::<_CMP_NLT_UQ>(cast!(a), cast!(b)))
3221 }
3222
3223 #[inline(always)]
3225 pub fn cmp_not_lt_f64x4(self, a: f64x4, b: f64x4) -> m64x4 {
3226 cast!(self.avx._mm256_cmp_pd::<_CMP_NLT_UQ>(cast!(a), cast!(b)))
3227 }
3228
3229 #[inline(always)]
3231 pub fn convert_f32x4_to_f64x4(self, a: f32x4) -> f64x4 {
3232 cast!(self.avx._mm256_cvtps_pd(cast!(a)))
3233 }
3234
3235 #[inline(always)]
3237 pub fn convert_f32x8_to_i32x8(self, a: f32x8) -> i32x8 {
3238 cast!(self.avx._mm256_cvttps_epi32(cast!(a)))
3239 }
3240
3241 #[inline(always)]
3243 pub fn convert_f64x4_to_f32x4(self, a: f64x4) -> f32x4 {
3244 cast!(self.avx._mm256_cvtpd_ps(cast!(a)))
3245 }
3246
3247 #[inline(always)]
3249 pub fn convert_f64x4_to_i32x4(self, a: f64x4) -> i32x4 {
3250 cast!(self.avx._mm256_cvttpd_epi32(cast!(a)))
3251 }
3252
3253 #[inline(always)]
3255 pub fn convert_i16x16_to_u16x16(self, a: i16x16) -> u16x16 {
3256 cast!(a)
3257 }
3258
3259 #[inline(always)]
3261 pub fn convert_i16x8_to_i32x8(self, a: i16x8) -> i32x8 {
3262 cast!(self.avx2._mm256_cvtepi16_epi32(cast!(a)))
3263 }
3264
3265 #[inline(always)]
3267 pub fn convert_i16x8_to_i64x4(self, a: i16x8) -> i64x4 {
3268 cast!(self.avx2._mm256_cvtepi16_epi64(cast!(a)))
3269 }
3270
3271 #[inline(always)]
3273 pub fn convert_i16x8_to_u32x8(self, a: i16x8) -> u32x8 {
3274 cast!(self.avx2._mm256_cvtepi16_epi32(cast!(a)))
3275 }
3276
3277 #[inline(always)]
3279 pub fn convert_i16x8_to_u64x4(self, a: i16x8) -> u64x4 {
3280 cast!(self.avx2._mm256_cvtepi16_epi64(cast!(a)))
3281 }
3282
3283 #[inline(always)]
3285 pub fn convert_i32x4_to_f64x4(self, a: i32x4) -> f64x4 {
3286 cast!(self.avx._mm256_cvtepi32_pd(cast!(a)))
3287 }
3288
3289 #[inline(always)]
3291 pub fn convert_i32x4_to_i64x4(self, a: i32x4) -> i64x4 {
3292 cast!(self.avx2._mm256_cvtepi32_epi64(cast!(a)))
3293 }
3294
3295 #[inline(always)]
3297 pub fn convert_i32x4_to_u64x4(self, a: i32x4) -> u64x4 {
3298 cast!(self.avx2._mm256_cvtepi32_epi64(cast!(a)))
3299 }
3300
3301 #[inline(always)]
3303 pub fn convert_i32x8_to_f32x8(self, a: i32x8) -> f32x8 {
3304 cast!(self.avx._mm256_cvtepi32_ps(cast!(a)))
3305 }
3306
3307 #[inline(always)]
3309 pub fn convert_i32x8_to_u32x8(self, a: i32x8) -> u32x8 {
3310 cast!(a)
3311 }
3312
3313 #[inline(always)]
3315 pub fn convert_i8x16_to_i16x16(self, a: i8x16) -> i16x16 {
3316 cast!(self.avx2._mm256_cvtepi8_epi16(cast!(a)))
3317 }
3318
3319 #[inline(always)]
3321 pub fn convert_i8x16_to_i32x8(self, a: i8x16) -> i32x8 {
3322 cast!(self.avx2._mm256_cvtepi8_epi32(cast!(a)))
3323 }
3324
3325 #[inline(always)]
3327 pub fn convert_i8x16_to_i64x4(self, a: i8x16) -> i64x4 {
3328 cast!(self.avx2._mm256_cvtepi8_epi64(cast!(a)))
3329 }
3330
3331 #[inline(always)]
3333 pub fn convert_i8x16_to_u16x16(self, a: i8x16) -> u16x16 {
3334 cast!(self.avx2._mm256_cvtepi8_epi16(cast!(a)))
3335 }
3336
3337 #[inline(always)]
3339 pub fn convert_i8x16_to_u32x8(self, a: i8x16) -> u32x8 {
3340 cast!(self.avx2._mm256_cvtepi8_epi32(cast!(a)))
3341 }
3342
3343 #[inline(always)]
3345 pub fn convert_i8x16_to_u64x4(self, a: i8x16) -> u64x4 {
3346 cast!(self.avx2._mm256_cvtepi8_epi64(cast!(a)))
3347 }
3348
3349 #[inline(always)]
3351 pub fn convert_i8x32_to_u8x32(self, a: i8x32) -> u8x32 {
3352 cast!(a)
3353 }
3354
3355 #[inline(always)]
3357 pub fn convert_u16x16_to_i16x16(self, a: u16x16) -> i16x16 {
3358 cast!(a)
3359 }
3360
3361 #[inline(always)]
3363 pub fn convert_u16x8_to_i32x8(self, a: u16x8) -> i32x8 {
3364 cast!(self.avx2._mm256_cvtepu16_epi32(cast!(a)))
3365 }
3366
3367 #[inline(always)]
3369 pub fn convert_u16x8_to_i64x4(self, a: u16x8) -> i64x4 {
3370 cast!(self.avx2._mm256_cvtepu16_epi64(cast!(a)))
3371 }
3372
3373 #[inline(always)]
3375 pub fn convert_u16x8_to_u32x8(self, a: u16x8) -> u32x8 {
3376 cast!(self.avx2._mm256_cvtepu16_epi32(cast!(a)))
3377 }
3378
3379 #[inline(always)]
3381 pub fn convert_u16x8_to_u64x4(self, a: u16x8) -> u64x4 {
3382 cast!(self.avx2._mm256_cvtepu16_epi64(cast!(a)))
3383 }
3384
3385 #[inline(always)]
3387 pub fn convert_u32x4_to_i64x4(self, a: u32x4) -> i64x4 {
3388 cast!(self.avx2._mm256_cvtepu32_epi64(cast!(a)))
3389 }
3390
3391 #[inline(always)]
3393 pub fn convert_u32x4_to_u64x4(self, a: u32x4) -> u64x4 {
3394 cast!(self.avx2._mm256_cvtepu32_epi64(cast!(a)))
3395 }
3396
3397 #[inline(always)]
3399 pub fn convert_u32x8_to_i32x8(self, a: u32x8) -> i32x8 {
3400 cast!(a)
3401 }
3402
3403 #[inline(always)]
3405 pub fn convert_u8x16_to_i16x16(self, a: u8x16) -> i16x16 {
3406 cast!(self.avx2._mm256_cvtepu8_epi16(cast!(a)))
3407 }
3408
3409 #[inline(always)]
3411 pub fn convert_u8x16_to_i32x8(self, a: u8x16) -> i32x8 {
3412 cast!(self.avx2._mm256_cvtepu8_epi32(cast!(a)))
3413 }
3414
3415 #[inline(always)]
3417 pub fn convert_u8x16_to_i64x4(self, a: u8x16) -> i64x4 {
3418 cast!(self.avx2._mm256_cvtepu8_epi64(cast!(a)))
3419 }
3420
3421 #[inline(always)]
3423 pub fn convert_u8x16_to_u16x16(self, a: u8x16) -> u16x16 {
3424 cast!(self.avx2._mm256_cvtepu8_epi16(cast!(a)))
3425 }
3426
3427 #[inline(always)]
3429 pub fn convert_u8x16_to_u32x8(self, a: u8x16) -> u32x8 {
3430 cast!(self.avx2._mm256_cvtepu8_epi32(cast!(a)))
3431 }
3432
3433 #[inline(always)]
3435 pub fn convert_u8x16_to_u64x4(self, a: u8x16) -> u64x4 {
3436 cast!(self.avx2._mm256_cvtepu8_epi64(cast!(a)))
3437 }
3438
3439 #[inline(always)]
3441 pub fn convert_u8x32_to_i8x32(self, a: u8x32) -> i8x32 {
3442 cast!(a)
3443 }
3444
3445 #[inline(always)]
3449 pub fn horizontal_saturating_add_pack_i16x16(self, a: i16x16, b: i16x16) -> i16x16 {
3450 cast!(self.avx2._mm256_hadds_epi16(cast!(a), cast!(b)))
3451 }
3452
3453 #[inline(always)]
3457 pub fn horizontal_saturating_sub_pack_i16x16(self, a: i16x16, b: i16x16) -> i16x16 {
3458 cast!(self.avx2._mm256_hsubs_epi16(cast!(a), cast!(b)))
3459 }
3460
3461 #[inline(always)]
3463 pub fn is_nan_f32x8(self, a: f32x8) -> m32x8 {
3464 cast!(self.avx._mm256_cmp_ps::<_CMP_UNORD_Q>(cast!(a), cast!(a)))
3465 }
3466
3467 #[inline(always)]
3469 pub fn is_nan_f64x4(self, a: f64x4) -> m64x4 {
3470 cast!(self.avx._mm256_cmp_pd::<_CMP_UNORD_Q>(cast!(a), cast!(a)))
3471 }
3472
3473 #[inline(always)]
3475 pub fn is_not_nan_f32x8(self, a: f32x8) -> m32x8 {
3476 cast!(self.avx._mm256_cmp_ps::<_CMP_ORD_Q>(cast!(a), cast!(a)))
3477 }
3478
3479 #[inline(always)]
3481 pub fn is_not_nan_f64x4(self, a: f64x4) -> m64x4 {
3482 cast!(self.avx._mm256_cmp_pd::<_CMP_ORD_Q>(cast!(a), cast!(a)))
3483 }
3484
3485 #[inline(always)]
3488 pub fn mul_add_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3489 cast!(self.fma._mm_fmadd_ps(cast!(a), cast!(b), cast!(c)))
3490 }
3491
3492 #[inline(always)]
3495 pub fn mul_add_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3496 cast!(self.fma._mm256_fmadd_ps(cast!(a), cast!(b), cast!(c)))
3497 }
3498
3499 #[inline(always)]
3502 pub fn mul_add_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3503 cast!(self.fma._mm_fmadd_pd(cast!(a), cast!(b), cast!(c)))
3504 }
3505
3506 #[inline(always)]
3509 pub fn mul_add_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3510 cast!(self.fma._mm256_fmadd_pd(cast!(a), cast!(b), cast!(c)))
3511 }
3512
3513 #[inline(always)]
3516 pub fn mul_addsub_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3517 cast!(self.fma._mm_fmsubadd_ps(cast!(a), cast!(b), cast!(c)))
3518 }
3519
3520 #[inline(always)]
3523 pub fn mul_addsub_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3524 cast!(self.fma._mm256_fmsubadd_ps(cast!(a), cast!(b), cast!(c)))
3525 }
3526
3527 #[inline(always)]
3530 pub fn mul_addsub_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3531 cast!(self.fma._mm_fmsubadd_pd(cast!(a), cast!(b), cast!(c)))
3532 }
3533
3534 #[inline(always)]
3537 pub fn mul_addsub_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3538 cast!(self.fma._mm256_fmsubadd_pd(cast!(a), cast!(b), cast!(c)))
3539 }
3540
3541 #[inline(always)]
3544 pub fn mul_sub_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3545 cast!(self.fma._mm_fmsub_ps(cast!(a), cast!(b), cast!(c)))
3546 }
3547
3548 #[inline(always)]
3551 pub fn mul_sub_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3552 cast!(self.fma._mm256_fmsub_ps(cast!(a), cast!(b), cast!(c)))
3553 }
3554
3555 #[inline(always)]
3558 pub fn mul_sub_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3559 cast!(self.fma._mm_fmsub_pd(cast!(a), cast!(b), cast!(c)))
3560 }
3561
3562 #[inline(always)]
3565 pub fn mul_sub_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3566 cast!(self.fma._mm256_fmsub_pd(cast!(a), cast!(b), cast!(c)))
3567 }
3568
3569 #[inline(always)]
3572 pub fn mul_subadd_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3573 cast!(self.fma._mm_fmaddsub_ps(cast!(a), cast!(b), cast!(c)))
3574 }
3575
3576 #[inline(always)]
3579 pub fn mul_subadd_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3580 cast!(self.fma._mm256_fmaddsub_ps(cast!(a), cast!(b), cast!(c)))
3581 }
3582
3583 #[inline(always)]
3586 pub fn mul_subadd_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3587 cast!(self.fma._mm_fmaddsub_pd(cast!(a), cast!(b), cast!(c)))
3588 }
3589
3590 #[inline(always)]
3593 pub fn mul_subadd_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3594 cast!(self.fma._mm256_fmaddsub_pd(cast!(a), cast!(b), cast!(c)))
3595 }
3596
3597 #[inline(always)]
3601 pub fn multiply_saturating_add_adjacent_i8x32(self, a: i8x32, b: i8x32) -> i16x16 {
3602 cast!(self.avx2._mm256_maddubs_epi16(cast!(a), cast!(b)))
3603 }
3604
3605 #[inline(always)]
3609 pub fn multiply_wrapping_add_adjacent_i16x16(self, a: i16x16, b: i16x16) -> i32x8 {
3610 cast!(self.avx2._mm256_madd_epi16(cast!(a), cast!(b)))
3611 }
3612
3613 #[inline(always)]
3617 pub fn multisum_of_absolute_differences_u8x32<const OFFSETS: i32>(
3618 self,
3619 a: u8x32,
3620 b: u8x32,
3621 ) -> u16x16 {
3622 cast!(self.avx2._mm256_mpsadbw_epu8::<OFFSETS>(cast!(a), cast!(b)))
3623 }
3624
3625 #[inline(always)]
3628 pub fn negate_mul_add_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3629 cast!(self.fma._mm_fnmadd_ps(cast!(a), cast!(b), cast!(c)))
3630 }
3631
3632 #[inline(always)]
3635 pub fn negate_mul_add_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3636 cast!(self.fma._mm256_fnmadd_ps(cast!(a), cast!(b), cast!(c)))
3637 }
3638
3639 #[inline(always)]
3642 pub fn negate_mul_add_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3643 cast!(self.fma._mm_fnmadd_pd(cast!(a), cast!(b), cast!(c)))
3644 }
3645
3646 #[inline(always)]
3649 pub fn negate_mul_add_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3650 cast!(self.fma._mm256_fnmadd_pd(cast!(a), cast!(b), cast!(c)))
3651 }
3652
3653 #[inline(always)]
3656 pub fn negate_mul_sub_f32x4(self, a: f32x4, b: f32x4, c: f32x4) -> f32x4 {
3657 cast!(self.fma._mm_fnmsub_ps(cast!(a), cast!(b), cast!(c)))
3658 }
3659
3660 #[inline(always)]
3663 pub fn negate_mul_sub_f32x8(self, a: f32x8, b: f32x8, c: f32x8) -> f32x8 {
3664 cast!(self.fma._mm256_fnmsub_ps(cast!(a), cast!(b), cast!(c)))
3665 }
3666
3667 #[inline(always)]
3670 pub fn negate_mul_sub_f64x2(self, a: f64x2, b: f64x2, c: f64x2) -> f64x2 {
3671 cast!(self.fma._mm_fnmsub_pd(cast!(a), cast!(b), cast!(c)))
3672 }
3673
3674 #[inline(always)]
3677 pub fn negate_mul_sub_f64x4(self, a: f64x4, b: f64x4, c: f64x4) -> f64x4 {
3678 cast!(self.fma._mm256_fnmsub_pd(cast!(a), cast!(b), cast!(c)))
3679 }
3680
3681 #[inline(always)]
3683 pub fn not_i16x16(self, a: i16x16) -> i16x16 {
3684 self.xor_i16x16(a, self.splat_i16x16(!0))
3685 }
3686
3687 #[inline(always)]
3689 pub fn not_i32x8(self, a: i32x8) -> i32x8 {
3690 self.xor_i32x8(a, self.splat_i32x8(!0))
3691 }
3692
3693 #[inline(always)]
3695 pub fn not_i64x4(self, a: i64x4) -> i64x4 {
3696 self.xor_i64x4(a, self.splat_i64x4(!0))
3697 }
3698
3699 #[inline(always)]
3701 pub fn not_i8x32(self, a: i8x32) -> i8x32 {
3702 self.xor_i8x32(a, self.splat_i8x32(!0))
3703 }
3704
3705 #[inline(always)]
3707 pub fn not_m16x16(self, a: m16x16) -> m16x16 {
3708 self.xor_m16x16(a, self.splat_m16x16(m16::new(true)))
3709 }
3710
3711 #[inline(always)]
3713 pub fn not_m32x8(self, a: m32x8) -> m32x8 {
3714 self.xor_m32x8(a, self.splat_m32x8(m32::new(true)))
3715 }
3716
3717 #[inline(always)]
3719 pub fn not_m64x4(self, a: m64x4) -> m64x4 {
3720 self.xor_m64x4(a, self.splat_m64x4(m64::new(true)))
3721 }
3722
3723 #[inline(always)]
3725 pub fn not_m8x32(self, a: m8x32) -> m8x32 {
3726 self.xor_m8x32(a, self.splat_m8x32(m8::new(true)))
3727 }
3728
3729 #[inline(always)]
3731 pub fn not_u16x16(self, a: u16x16) -> u16x16 {
3732 self.xor_u16x16(a, self.splat_u16x16(!0))
3733 }
3734
3735 #[inline(always)]
3737 pub fn not_u32x8(self, a: u32x8) -> u32x8 {
3738 self.xor_u32x8(a, self.splat_u32x8(!0))
3739 }
3740
3741 #[inline(always)]
3743 pub fn not_u64x4(self, a: u64x4) -> u64x4 {
3744 self.xor_u64x4(a, self.splat_u64x4(!0))
3745 }
3746
3747 #[inline(always)]
3749 pub fn not_u8x32(self, a: u8x32) -> u8x32 {
3750 self.xor_u8x32(a, self.splat_u8x32(!0))
3751 }
3752
3753 #[inline(always)]
3757 pub fn pack_with_signed_saturation_i16x16(self, a: i16x16, b: i16x16) -> i8x32 {
3758 cast!(self.avx2._mm256_packs_epi16(cast!(a), cast!(b)))
3759 }
3760
3761 #[inline(always)]
3765 pub fn pack_with_signed_saturation_i32x8(self, a: i32x8, b: i32x8) -> i16x16 {
3766 cast!(self.avx2._mm256_packs_epi32(cast!(a), cast!(b)))
3767 }
3768
3769 #[inline(always)]
3773 pub fn pack_with_unsigned_saturation_i16x16(self, a: i16x16, b: i16x16) -> u8x32 {
3774 cast!(self.avx2._mm256_packus_epi16(cast!(a), cast!(b)))
3775 }
3776
3777 #[inline(always)]
3781 pub fn pack_with_unsigned_saturation_i32x8(self, a: i32x8, b: i32x8) -> u16x16 {
3782 cast!(self.avx2._mm256_packus_epi32(cast!(a), cast!(b)))
3783 }
3784
3785 #[inline(always)]
3788 pub fn round_f32x8(self, a: f32x8) -> f32x8 {
3789 const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
3790 cast!(self.avx._mm256_round_ps::<ROUNDING>(cast!(a)))
3791 }
3792
3793 #[inline(always)]
3796 pub fn round_f64x4(self, a: f64x4) -> f64x4 {
3797 const ROUNDING: i32 = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
3798 cast!(self.avx._mm256_round_pd::<ROUNDING>(cast!(a)))
3799 }
3800
3801 #[inline(always)]
3804 pub fn select_const_f32x8<const MASK8: i32>(self, if_true: f32x8, if_false: f32x8) -> f32x8 {
3805 cast!(
3806 self.avx
3807 ._mm256_blend_ps::<MASK8>(cast!(if_false), cast!(if_true)),
3808 )
3809 }
3810
3811 #[inline(always)]
3814 pub fn select_const_f64x4<const MASK4: i32>(self, if_true: f64x4, if_false: f64x4) -> f64x4 {
3815 cast!(self.select_const_u64x4::<MASK4>(cast!(if_true), cast!(if_false)))
3816 }
3817
3818 #[inline(always)]
3821 pub fn select_const_i32x8<const MASK8: i32>(self, if_true: i32x8, if_false: i32x8) -> i32x8 {
3822 cast!(self.select_const_u32x8::<MASK8>(cast!(if_true), cast!(if_false)))
3823 }
3824
3825 #[inline(always)]
3828 pub fn select_const_i64x4<const MASK4: i32>(self, if_true: i64x4, if_false: i64x4) -> i64x4 {
3829 cast!(self.select_const_u64x4::<MASK4>(cast!(if_true), cast!(if_false)))
3830 }
3831
3832 #[inline(always)]
3835 pub fn select_const_u32x8<const MASK8: i32>(self, if_true: u32x8, if_false: u32x8) -> u32x8 {
3836 cast!(
3837 self.avx2
3838 ._mm256_blend_epi32::<MASK8>(cast!(if_false), cast!(if_true)),
3839 )
3840 }
3841
3842 #[inline(always)]
3845 pub fn select_const_u64x4<const MASK4: i32>(self, if_true: u64x4, if_false: u64x4) -> u64x4 {
3846 cast!(
3847 self.avx
3848 ._mm256_blend_pd::<MASK4>(cast!(if_false), cast!(if_true)),
3849 )
3850 }
3851
3852 #[inline(always)]
3855 pub fn select_f32x8(self, mask: m32x8, if_true: f32x8, if_false: f32x8) -> f32x8 {
3856 cast!(
3857 self.avx
3858 ._mm256_blendv_ps(cast!(if_false), cast!(if_true), cast!(mask)),
3859 )
3860 }
3861
3862 #[inline(always)]
3865 pub fn select_f64x4(self, mask: m64x4, if_true: f64x4, if_false: f64x4) -> f64x4 {
3866 cast!(
3867 self.avx
3868 ._mm256_blendv_pd(cast!(if_false), cast!(if_true), cast!(mask)),
3869 )
3870 }
3871
3872 #[inline(always)]
3875 pub fn select_i16x16(self, mask: m16x16, if_true: i16x16, if_false: i16x16) -> i16x16 {
3876 cast!(self.select_u16x16(mask, cast!(if_true), cast!(if_false)))
3877 }
3878
3879 #[inline(always)]
3882 pub fn select_i32x8(self, mask: m32x8, if_true: i32x8, if_false: i32x8) -> i32x8 {
3883 cast!(self.select_u32x8(mask, cast!(if_true), cast!(if_false)))
3884 }
3885
3886 #[inline(always)]
3889 pub fn select_i64x4(self, mask: m64x4, if_true: i64x4, if_false: i64x4) -> i64x4 {
3890 cast!(self.select_u64x4(mask, cast!(if_true), cast!(if_false)))
3891 }
3892
3893 #[inline(always)]
3896 pub fn select_i8x32(self, mask: m8x32, if_true: i8x32, if_false: i8x32) -> i8x32 {
3897 cast!(self.select_u8x32(mask, cast!(if_true), cast!(if_false)))
3898 }
3899
3900 #[inline(always)]
3903 pub fn select_u16x16(self, mask: m16x16, if_true: u16x16, if_false: u16x16) -> u16x16 {
3904 cast!(
3905 self.avx2
3906 ._mm256_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
3907 )
3908 }
3909
3910 #[inline(always)]
3913 pub fn select_u32x8(self, mask: m32x8, if_true: u32x8, if_false: u32x8) -> u32x8 {
3914 cast!(
3915 self.avx2
3916 ._mm256_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
3917 )
3918 }
3919
3920 #[inline(always)]
3923 pub fn select_u64x4(self, mask: m64x4, if_true: u64x4, if_false: u64x4) -> u64x4 {
3924 cast!(
3925 self.avx2
3926 ._mm256_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
3927 )
3928 }
3929
3930 #[inline(always)]
3933 pub fn select_u8x32(self, mask: m8x32, if_true: u8x32, if_false: u8x32) -> u8x32 {
3934 cast!(
3935 self.avx2
3936 ._mm256_blendv_epi8(cast!(if_false), cast!(if_true), cast!(mask)),
3937 )
3938 }
3939
3940 #[inline(always)]
3943 pub fn shl_const_i16x16<const AMOUNT: i32>(self, a: i16x16) -> i16x16 {
3944 cast!(self.avx2._mm256_slli_epi16::<AMOUNT>(cast!(a)))
3945 }
3946
3947 #[inline(always)]
3950 pub fn shl_const_i32x8<const AMOUNT: i32>(self, a: i32x8) -> i32x8 {
3951 cast!(self.avx2._mm256_slli_epi32::<AMOUNT>(cast!(a)))
3952 }
3953
3954 #[inline(always)]
3957 pub fn shl_const_i64x4<const AMOUNT: i32>(self, a: i64x4) -> i64x4 {
3958 cast!(self.avx2._mm256_slli_epi64::<AMOUNT>(cast!(a)))
3959 }
3960
3961 #[inline(always)]
3964 pub fn shl_const_u16x16<const AMOUNT: i32>(self, a: u16x16) -> u16x16 {
3965 cast!(self.avx2._mm256_slli_epi16::<AMOUNT>(cast!(a)))
3966 }
3967
3968 #[inline(always)]
3971 pub fn shl_const_u32x8<const AMOUNT: i32>(self, a: u32x8) -> u32x8 {
3972 cast!(self.avx2._mm256_slli_epi32::<AMOUNT>(cast!(a)))
3973 }
3974
3975 #[inline(always)]
3978 pub fn shl_const_u64x4<const AMOUNT: i32>(self, a: u64x4) -> u64x4 {
3979 cast!(self.avx2._mm256_slli_epi64::<AMOUNT>(cast!(a)))
3980 }
3981
3982 #[inline(always)]
3986 pub fn shl_dyn_i32x4(self, a: i32x4, amount: u32x4) -> i32x4 {
3987 cast!(self.avx2._mm_sllv_epi32(cast!(a), cast!(amount)))
3988 }
3989
3990 #[inline(always)]
3994 pub fn shl_dyn_i32x8(self, a: i32x8, amount: u32x8) -> i32x8 {
3995 cast!(self.avx2._mm256_sllv_epi32(cast!(a), cast!(amount)))
3996 }
3997
3998 #[inline(always)]
4002 pub fn shl_dyn_i64x2(self, a: i64x2, amount: u64x2) -> i64x2 {
4003 cast!(self.avx2._mm_sllv_epi64(cast!(a), cast!(amount)))
4004 }
4005
4006 #[inline(always)]
4010 pub fn shl_dyn_i64x4(self, a: i64x4, amount: u64x4) -> i64x4 {
4011 cast!(self.avx2._mm256_sllv_epi64(cast!(a), cast!(amount)))
4012 }
4013
4014 #[inline(always)]
4018 pub fn shl_dyn_u32x4(self, a: u32x4, amount: u32x4) -> u32x4 {
4019 cast!(self.avx2._mm_sllv_epi32(cast!(a), cast!(amount)))
4020 }
4021
4022 #[inline(always)]
4026 pub fn shl_dyn_u32x8(self, a: u32x8, amount: u32x8) -> u32x8 {
4027 cast!(self.avx2._mm256_sllv_epi32(cast!(a), cast!(amount)))
4028 }
4029
4030 #[inline(always)]
4034 pub fn shl_dyn_u64x2(self, a: u64x2, amount: u64x2) -> u64x2 {
4035 cast!(self.avx2._mm_sllv_epi64(cast!(a), cast!(amount)))
4036 }
4037
4038 #[inline(always)]
4042 pub fn shl_dyn_u64x4(self, a: u64x4, amount: u64x4) -> u64x4 {
4043 cast!(self.avx2._mm256_sllv_epi64(cast!(a), cast!(amount)))
4044 }
4045
4046 #[inline(always)]
4050 pub fn shl_i16x16(self, a: i16x16, amount: u64x2) -> i16x16 {
4051 cast!(self.avx2._mm256_sll_epi16(cast!(a), cast!(amount)))
4052 }
4053
4054 #[inline(always)]
4058 pub fn shl_i32x8(self, a: i32x8, amount: u64x2) -> i32x8 {
4059 cast!(self.avx2._mm256_sll_epi32(cast!(a), cast!(amount)))
4060 }
4061
4062 #[inline(always)]
4066 pub fn shl_i64x4(self, a: i64x4, amount: u64x2) -> i64x4 {
4067 cast!(self.avx2._mm256_sll_epi64(cast!(a), cast!(amount)))
4068 }
4069
4070 #[inline(always)]
4074 pub fn shl_u16x16(self, a: u16x16, amount: u64x2) -> u16x16 {
4075 cast!(self.avx2._mm256_sll_epi16(cast!(a), cast!(amount)))
4076 }
4077
4078 #[inline(always)]
4082 pub fn shl_u32x8(self, a: u32x8, amount: u64x2) -> u32x8 {
4083 cast!(self.avx2._mm256_sll_epi32(cast!(a), cast!(amount)))
4084 }
4085
4086 #[inline(always)]
4090 pub fn shl_u64x4(self, a: u64x4, amount: u64x2) -> u64x4 {
4091 cast!(self.avx2._mm256_sll_epi64(cast!(a), cast!(amount)))
4092 }
4093
4094 #[inline(always)]
4098 pub fn shr_const_i16x16<const AMOUNT: i32>(self, a: i16x16) -> i16x16 {
4099 cast!(self.avx2._mm256_srai_epi16::<AMOUNT>(cast!(a)))
4100 }
4101
4102 #[inline(always)]
4106 pub fn shr_const_i32x8<const AMOUNT: i32>(self, a: i32x8) -> i32x8 {
4107 cast!(self.avx2._mm256_srai_epi32::<AMOUNT>(cast!(a)))
4108 }
4109
4110 #[inline(always)]
4113 pub fn shr_const_u16x16<const AMOUNT: i32>(self, a: u16x16) -> u16x16 {
4114 cast!(self.avx2._mm256_srli_epi16::<AMOUNT>(cast!(a)))
4115 }
4116
4117 #[inline(always)]
4120 pub fn shr_const_u32x8<const AMOUNT: i32>(self, a: u32x8) -> u32x8 {
4121 cast!(self.avx2._mm256_srli_epi32::<AMOUNT>(cast!(a)))
4122 }
4123
4124 #[inline(always)]
4127 pub fn shr_const_u64x4<const AMOUNT: i32>(self, a: u64x4) -> u64x4 {
4128 cast!(self.avx2._mm256_srli_epi64::<AMOUNT>(cast!(a)))
4129 }
4130
4131 #[inline(always)]
4136 pub fn shr_dyn_i32x4(self, a: i32x4, amount: u32x4) -> i32x4 {
4137 cast!(self.avx2._mm_srav_epi32(cast!(a), cast!(amount)))
4138 }
4139
4140 #[inline(always)]
4145 pub fn shr_dyn_i32x8(self, a: i32x8, amount: u32x8) -> i32x8 {
4146 cast!(self.avx2._mm256_srav_epi32(cast!(a), cast!(amount)))
4147 }
4148
4149 #[inline(always)]
4153 pub fn shr_dyn_u32x4(self, a: u32x4, amount: u32x4) -> u32x4 {
4154 cast!(self.avx2._mm_srlv_epi32(cast!(a), cast!(amount)))
4155 }
4156
4157 #[inline(always)]
4161 pub fn shr_dyn_u32x8(self, a: u32x8, amount: u32x8) -> u32x8 {
4162 cast!(self.avx2._mm256_srlv_epi32(cast!(a), cast!(amount)))
4163 }
4164
4165 #[inline(always)]
4169 pub fn shr_dyn_u64x2(self, a: u64x2, amount: u64x2) -> u64x2 {
4170 cast!(self.avx2._mm_srlv_epi64(cast!(a), cast!(amount)))
4171 }
4172
4173 #[inline(always)]
4177 pub fn shr_dyn_u64x4(self, a: u64x4, amount: u64x4) -> u64x4 {
4178 cast!(self.avx2._mm256_srlv_epi64(cast!(a), cast!(amount)))
4179 }
4180
4181 #[inline(always)]
4186 pub fn shr_i16x16(self, a: i16x16, amount: u64x2) -> i16x16 {
4187 cast!(self.avx2._mm256_sra_epi16(cast!(a), cast!(amount)))
4188 }
4189
4190 #[inline(always)]
4195 pub fn shr_i32x8(self, a: i32x8, amount: u64x2) -> i32x8 {
4196 cast!(self.avx2._mm256_sra_epi32(cast!(a), cast!(amount)))
4197 }
4198
4199 #[inline(always)]
4203 pub fn shr_u16x16(self, a: u16x16, amount: u64x2) -> u16x16 {
4204 cast!(self.avx2._mm256_srl_epi16(cast!(a), cast!(amount)))
4205 }
4206
4207 #[inline(always)]
4211 pub fn shr_u32x8(self, a: u32x8, amount: u64x2) -> u32x8 {
4212 cast!(self.avx2._mm256_srl_epi32(cast!(a), cast!(amount)))
4213 }
4214
4215 #[inline(always)]
4219 pub fn shr_u64x4(self, a: u64x4, amount: u64x2) -> u64x4 {
4220 cast!(self.avx2._mm256_srl_epi64(cast!(a), cast!(amount)))
4221 }
4222
4223 #[inline(always)]
4225 pub fn splat_f32x8(self, value: f32) -> f32x8 {
4226 cast!(self.avx._mm256_set1_ps(value))
4227 }
4228
4229 #[inline(always)]
4231 pub fn splat_f64x4(self, value: f64) -> f64x4 {
4232 cast!(self.avx._mm256_set1_pd(value))
4233 }
4234
4235 #[inline(always)]
4237 pub fn splat_i16x16(self, value: i16) -> i16x16 {
4238 cast!(self.avx._mm256_set1_epi16(value))
4239 }
4240
4241 #[inline(always)]
4243 pub fn splat_i32x8(self, value: i32) -> i32x8 {
4244 cast!(self.avx._mm256_set1_epi32(value))
4245 }
4246
4247 #[inline(always)]
4249 pub fn splat_i64x4(self, value: i64) -> i64x4 {
4250 cast!(self.avx._mm256_set1_epi64x(value))
4251 }
4252
4253 #[inline(always)]
4255 pub fn splat_i8x32(self, value: i8) -> i8x32 {
4256 cast!(self.avx._mm256_set1_epi8(value))
4257 }
4258
4259 #[inline(always)]
4261 pub fn splat_m16x16(self, value: m16) -> m16x16 {
4262 cast!(self.avx._mm256_set1_epi16(value.0 as i16))
4263 }
4264
4265 #[inline(always)]
4267 pub fn splat_m32x8(self, value: m32) -> m32x8 {
4268 cast!(self.avx._mm256_set1_epi32(value.0 as i32))
4269 }
4270
4271 #[inline(always)]
4273 pub fn splat_m64x4(self, value: m64) -> m64x4 {
4274 cast!(self.avx._mm256_set1_epi64x(value.0 as i64))
4275 }
4276
4277 #[inline(always)]
4279 pub fn splat_m8x32(self, value: m8) -> m8x32 {
4280 cast!(self.avx._mm256_set1_epi8(value.0 as i8))
4281 }
4282
4283 #[inline(always)]
4285 pub fn splat_u16x16(self, value: u16) -> u16x16 {
4286 cast!(self.avx._mm256_set1_epi16(value as i16))
4287 }
4288
4289 #[inline(always)]
4291 pub fn splat_u32x8(self, value: u32) -> u32x8 {
4292 cast!(self.avx._mm256_set1_epi32(value as i32))
4293 }
4294
4295 #[inline(always)]
4297 pub fn splat_u64x4(self, value: u64) -> u64x4 {
4298 cast!(self.avx._mm256_set1_epi64x(value as i64))
4299 }
4300
4301 #[inline(always)]
4303 pub fn splat_u8x32(self, value: u8) -> u8x32 {
4304 cast!(self.avx._mm256_set1_epi8(value as i8))
4305 }
4306
4307 #[inline(always)]
4309 pub fn sqrt_f32x8(self, a: f32x8) -> f32x8 {
4310 cast!(self.avx._mm256_sqrt_ps(cast!(a)))
4311 }
4312
4313 #[inline(always)]
4315 pub fn sqrt_f64x4(self, a: f64x4) -> f64x4 {
4316 cast!(self.avx._mm256_sqrt_pd(cast!(a)))
4317 }
4318
4319 #[inline(always)]
4323 pub fn sum_of_absolute_differences_u8x32(self, a: u8x32, b: u8x32) -> u64x4 {
4324 cast!(self.avx2._mm256_sad_epu8(cast!(a), cast!(b)))
4325 }
4326
4327 #[inline(always)]
4329 pub fn truncate_f32x8(self, a: f32x8) -> f32x8 {
4330 const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
4331 cast!(self.avx._mm256_round_ps::<ROUNDING>(cast!(a)))
4332 }
4333
4334 #[inline(always)]
4336 pub fn truncate_f64x4(self, a: f64x4) -> f64x4 {
4337 const ROUNDING: i32 = _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC;
4338 cast!(self.avx._mm256_round_pd::<ROUNDING>(cast!(a)))
4339 }
4340
4341 #[inline(always)]
4344 pub fn widening_mul_i16x16(self, a: i16x16, b: i16x16) -> (u16x16, i16x16) {
4345 (
4346 cast!(self.avx2._mm256_mullo_epi16(cast!(a), cast!(b))),
4347 cast!(self.avx2._mm256_mulhi_epi16(cast!(a), cast!(b))),
4348 )
4349 }
4350
4351 #[inline(always)]
4354 pub fn widening_mul_i32x8(self, a: i32x8, b: i32x8) -> (u32x8, i32x8) {
4355 let a = cast!(a);
4356 let b = cast!(b);
4357 let avx2 = self.avx2;
4358
4359 let ab_evens = self.avx2._mm256_mul_epi32(a, b);
4361 let ab_odds = self.avx2._mm256_mul_epi32(
4363 avx2._mm256_srli_epi64::<32>(a),
4364 avx2._mm256_srli_epi64::<32>(b),
4365 );
4366
4367 let ab_lo = self.avx2._mm256_blend_epi32::<0b10101010>(
4368 ab_evens,
4370 avx2._mm256_slli_epi64::<32>(ab_odds),
4372 );
4373 let ab_hi = self.avx2._mm256_blend_epi32::<0b10101010>(
4374 avx2._mm256_srli_epi64::<32>(ab_evens),
4376 ab_odds,
4378 );
4379
4380 (cast!(ab_lo), cast!(ab_hi))
4381 }
4382
4383 #[inline(always)]
4386 pub fn widening_mul_u16x16(self, a: u16x16, b: u16x16) -> (u16x16, u16x16) {
4387 (
4388 cast!(self.avx2._mm256_mullo_epi16(cast!(a), cast!(b))),
4389 cast!(self.avx2._mm256_mulhi_epu16(cast!(a), cast!(b))),
4390 )
4391 }
4392
4393 #[inline(always)]
4396 pub fn widening_mul_u32x8(self, a: u32x8, b: u32x8) -> (u32x8, u32x8) {
4397 let a = cast!(a);
4398 let b = cast!(b);
4399 let avx2 = self.avx2;
4400
4401 let ab_evens = avx2._mm256_mul_epu32(a, b);
4403 let ab_odds = avx2._mm256_mul_epu32(
4405 avx2._mm256_srli_epi64::<32>(a),
4406 avx2._mm256_srli_epi64::<32>(b),
4407 );
4408
4409 let ab_lo = self.avx2._mm256_blend_epi32::<0b10101010>(
4410 ab_evens,
4412 avx2._mm256_slli_epi64::<32>(ab_odds),
4414 );
4415 let ab_hi = self.avx2._mm256_blend_epi32::<0b10101010>(
4416 avx2._mm256_srli_epi64::<32>(ab_evens),
4418 ab_odds,
4420 );
4421
4422 (cast!(ab_lo), cast!(ab_hi))
4423 }
4424}