Skip to main content

pulp/x86/
v3.rs

1use super::*;
2
3// https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
4simd_type!({
5	/// AVX instruction set.
6	///
7	/// Notable additions over [`V2`] include:
8	///  - Instructions operating on 256-bit SIMD vectors.
9	///  - Shift functions with a separate shift per lane, such as [`V3::shl_dyn_u32x4`].
10	///  - Fused multiply-accumulate instructions, such as [`V3::mul_add_f32x4`].
11	#[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// copied from the standard library
31#[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	// This is ordering sensitive, and LLVM will order these how you put them.
36	// Most AVX2 impls use ~5 "ports", and only 1 or 2 are capable of permutes.
37	// But the "compose" step will lower to ops that can also use at least 1 other port.
38	// So this tries to break up permutes so composition flows through "open" ports.
39	// Comparative benches should be done on multiple AVX2 CPUs before reordering this
40
41	let hihi = simd.avx2._mm256_permute2x128_si256::<0x11>(bytes, bytes);
42	let hi_shuf = simd.avx2._mm256_shuffle_epi8(
43		hihi, // duplicate the vector's top half
44		idxs, // so that using only 4 bits of an index still picks bytes 16-31
45	);
46	// A zero-fill during the compose step gives the "all-Neon-like" OOB-is-0 semantics
47	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	// Repeat, then pick indices < 16, overwriting indices 0-15 from previous compose step
55	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			// a0 b0 a1 b1 a2 b2 a3 b3
539			// a4 b4 a5 b5 a6 b6 a7 b7
540
541			// a0 a4 b0 b4 a2 a6 b2 b6
542			// a1 a5 b1 b5 a3 a7 b3 b7
543			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			// a0 a4 a1 a5 a2 a6 a3 a7
549			// b0 b4 b1 b5 b2 b6 b3 b7
550			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			// a0 b0 c0 d0 a1 b1 c1 d1
558			// a2 b2 c2 d2 a3 b3 c3 d3
559			// a4 b4 c4 d4 a5 b5 c5 d5
560			// a6 b6 c6 d6 a7 b7 c7 d7
561			let values: [__m256d; 4] = unsafe { core::mem::transmute_copy(&values) };
562
563			// a0 a2 c0 c2 a1 a3 c1 c3
564			// b0 b2 d0 d2 b1 b3 d1 d3
565			// a4 a6 c4 c6 a5 a7 c5 c7
566			// b4 b6 d4 d6 b5 b7 d5 d7
567			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			// a0 a2 a4 a6 a1 a3 a5 a7
582			// b0 b2 b4 b6 b1 b3 b5 b7
583			// c0 c2 c4 c6 c1 c3 c5 c7
584			// d0 d2 d4 d6 d1 d3 d5 d7
585			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			// a0 b0 c0 d0
613			// a1 b1 c1 d1
614			// a2 b2 c2 d2
615			// a3 b3 c3 d3
616
617			// a0 a1 c0 c1
618			// b0 b1 d0 d1
619			// a2 a3 c2 c3
620			// b2 b3 d2 d3
621			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			// a0 a1 a2 a3
629			// b0 b1 b2 b3
630			// c0 c1 c2 c3
631			// d0 d1 d2 d3
632			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			// permutation is inverse of itself in this case
652			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			// permutation is inverse of itself in this case
665			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	/// # Safety
704	///
705	/// See the trait-level safety documentation.
706	#[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	/// # Safety
712	///
713	/// See the trait-level safety documentation.
714	#[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	/// # Safety
720	///
721	/// See the trait-level safety documentation.
722	#[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	/// # Safety
728	///
729	/// See the trait-level safety documentation.
730	#[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	/// # Safety
736	///
737	/// See the trait-level safety documentation.
738	#[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	/// # Safety
748	///
749	/// See the trait-level safety documentation.
750	#[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	/// # Safety
760	///
761	/// See the trait-level safety documentation.
762	#[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	/// # Safety
773	///
774	/// See the trait-level safety documentation.
775	#[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	/// # Safety
786	///
787	/// See the trait-level safety documentation.
788	#[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	/// # Safety
794	///
795	/// See the trait-level safety documentation.
796	#[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	/// # Safety
807	///
808	/// See the trait-level safety documentation.
809	#[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	/// # Safety
824	///
825	/// See the trait-level safety documentation.
826	#[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		// a0 a1 a2 a3
1800		let a: __m128 = cast!(a);
1801		// a2 a3 a2 a3
1802		let hi = self.sse._mm_movehl_ps(a, a);
1803
1804		// a0+a2 a1+a3 _ _
1805		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		/// # Safety
2020		///
2021		/// See the trait-level safety documentation.
2022		unsafe fn mask_load_ptr_c32s(
2023			self,
2024			mask: MemMask<Self::m32s>,
2025			ptr: *const c32,
2026		) -> Self::c32s;
2027		/// # Safety
2028		///
2029		/// See the trait-level safety documentation.
2030		unsafe fn mask_load_ptr_c64s(
2031			self,
2032			mask: MemMask<Self::m64s>,
2033			ptr: *const c64,
2034		) -> Self::c64s;
2035		/// # Safety
2036		///
2037		/// See the trait-level safety documentation.
2038		unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s;
2039		/// # Safety
2040		///
2041		/// See the trait-level safety documentation.
2042		unsafe fn mask_load_ptr_u16s(
2043			self,
2044			mask: MemMask<Self::m16s>,
2045			ptr: *const u16,
2046		) -> Self::u16s;
2047		/// # Safety
2048		///
2049		/// See the trait-level safety documentation.
2050		unsafe fn mask_load_ptr_u32s(
2051			self,
2052			mask: MemMask<Self::m32s>,
2053			ptr: *const u32,
2054		) -> Self::u32s;
2055		/// # Safety
2056		///
2057		/// See the trait-level safety documentation.
2058		unsafe fn mask_load_ptr_u64s(
2059			self,
2060			mask: MemMask<Self::m64s>,
2061			ptr: *const u64,
2062		) -> Self::u64s;
2063		/// # Safety
2064		///
2065		/// See the trait-level safety documentation.
2066		unsafe fn mask_store_ptr_c32s(
2067			self,
2068			mask: MemMask<Self::m32s>,
2069			ptr: *mut c32,
2070			values: Self::c32s,
2071		);
2072		/// # Safety
2073		///
2074		/// See the trait-level safety documentation.
2075		unsafe fn mask_store_ptr_c64s(
2076			self,
2077			mask: MemMask<Self::m64s>,
2078			ptr: *mut c64,
2079			values: Self::c64s,
2080		);
2081		/// # Safety
2082		///
2083		/// See the trait-level safety documentation.
2084		unsafe fn mask_store_ptr_u8s(
2085			self,
2086			mask: MemMask<Self::m8s>,
2087			ptr: *mut u8,
2088			values: Self::u8s,
2089		);
2090		/// # Safety
2091		///
2092		/// See the trait-level safety documentation.
2093		unsafe fn mask_store_ptr_u16s(
2094			self,
2095			mask: MemMask<Self::m16s>,
2096			ptr: *mut u16,
2097			values: Self::u16s,
2098		);
2099		/// # Safety
2100		///
2101		/// See the trait-level safety documentation.
2102		unsafe fn mask_store_ptr_u32s(
2103			self,
2104			mask: MemMask<Self::m32s>,
2105			ptr: *mut u32,
2106			values: Self::u32s,
2107		);
2108		/// # Safety
2109		///
2110		/// See the trait-level safety documentation.
2111		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	/// # Safety
2493	///
2494	/// See the trait-level safety documentation.
2495	#[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	/// # Safety
2506	///
2507	/// See the trait-level safety documentation.
2508	#[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	/// # Safety
2519	///
2520	/// See the trait-level safety documentation.
2521	#[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	/// # Safety
2532	///
2533	/// See the trait-level safety documentation.
2534	#[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	/// # Safety
2545	///
2546	/// See the trait-level safety documentation.
2547	#[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	/// # Safety
2558	///
2559	/// See the trait-level safety documentation.
2560	#[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	/// # Safety
2571	///
2572	/// See the trait-level safety documentation.
2573	#[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	/// # Safety
2594	///
2595	/// See the trait-level safety documentation.
2596	#[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	/// # Safety
2617	///
2618	/// See the trait-level safety documentation.
2619	#[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	/// # Safety
2635	///
2636	/// See the trait-level safety documentation.
2637	#[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	/// # Safety
2658	///
2659	/// See the trait-level safety documentation.
2660	#[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	/// # Safety
2681	///
2682	/// See the trait-level safety documentation.
2683	#[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	/// Computes `abs(a)` for each lane of `a`.
2910	#[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	/// Computes `abs(a)` for each lane of `a`.
2916	#[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	/// Computes the approximate reciprocal of the elements of each lane of `a`.
2922	#[inline(always)]
2923	pub fn approx_reciprocal_f32x8(self, a: f32x8) -> f32x8 {
2924		cast!(self.avx._mm256_rcp_ps(cast!(a)))
2925	}
2926
2927	/// Computes the approximate reciprocal of the square roots of the elements of each lane of `a`.
2928	#[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	/// Compares the elements in each lane of `a` and `b` for equality.
2934	#[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	/// Compares the elements in each lane of `a` and `b` for equality.
2940	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2946	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2952	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2958	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2964	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2970	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2976	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2982	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2988	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
2994	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than-or-equal-to.
3000	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3006	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3012	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3018	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3025	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3032	#[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	/// Compares the elements in each lane of `a` and `b` for greater-than.
3039	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3046	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3052	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3058	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3064	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3070	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3076	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3082	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3088	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3094	#[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	/// Compares the elements in each lane of `a` and `b` for less-than-or-equal-to.
3100	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3106	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3112	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3118	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3124	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3130	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3136	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3142	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3149	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3156	#[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	/// Compares the elements in each lane of `a` and `b` for less-than.
3163	#[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	/// Compares the elements in each lane of `a` and `b` for inequality.
3170	#[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	/// Compares the elements in each lane of `a` and `b` for inequality.
3176	#[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	/// Compares the elements in each lane of `a` and `b` for not-greater-than-or-equal.
3182	#[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	/// Compares the elements in each lane of `a` and `b` for not-greater-than-or-equal.
3188	#[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	/// Compares the elements in each lane of `a` and `b` for not-greater-than.
3194	#[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	/// Compares the elements in each lane of `a` and `b` for not-greater-than.
3200	#[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	/// Compares the elements in each lane of `a` and `b` for not-less-than-or-equal.
3206	#[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	/// Compares the elements in each lane of `a` and `b` for not-less-than-or-equal.
3212	#[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	/// Compares the elements in each lane of `a` and `b` for not-less-than.
3218	#[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	/// Compares the elements in each lane of `a` and `b` for not-less-than.
3224	#[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	/// Converts a `f32x4` to `f64x4`, elementwise.
3230	#[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	/// Converts a `f32x8` to `i32x8`, elementwise.
3236	#[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	/// Converts a `f64x4` to `f32x4`, elementwise.
3242	#[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	/// Converts a `f64x4` to `i32x4`, elementwise.
3248	#[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	/// Converts a `i16x16` to `u16x16`, elementwise.
3254	#[inline(always)]
3255	pub fn convert_i16x16_to_u16x16(self, a: i16x16) -> u16x16 {
3256		cast!(a)
3257	}
3258
3259	/// Converts a `i16x8` to `i32x8`, elementwise.
3260	#[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	/// Converts a `i16x8` to `i64x4`, elementwise, while truncating the extra elements.
3266	#[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	/// Converts a `i16x8` to `u32x8`, elementwise.
3272	#[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	/// Converts a `i16x8` to `u64x4`, elementwise, while truncating the extra elements.
3278	#[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	/// Converts a `i32x4` to `f64x4`, elementwise.
3284	#[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	/// Converts a `i32x4` to `i64x4`, elementwise.
3290	#[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	/// Converts a `i32x4` to `u64x4`, elementwise.
3296	#[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	/// Converts a `i32x8` to `f32x8`, elementwise.
3302	#[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	/// Converts a `i32x8` to `u32x8`, elementwise.
3308	#[inline(always)]
3309	pub fn convert_i32x8_to_u32x8(self, a: i32x8) -> u32x8 {
3310		cast!(a)
3311	}
3312
3313	/// Converts a `i8x16` to `i16x16`, elementwise.
3314	#[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	/// Converts a `i8x16` to `i32x8`, elementwise, while truncating the extra elements.
3320	#[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	/// Converts a `i8x16` to `i64x4`, elementwise, while truncating the extra elements.
3326	#[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	/// Converts a `i8x16` to `u16x16`, elementwise.
3332	#[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	/// Converts a `i8x16` to `u32x8`, elementwise, while truncating the extra elements.
3338	#[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	/// Converts a `i8x16` to `u64x4`, elementwise, while truncating the extra elements.
3344	#[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	/// Converts a `i8x32` to `u8x32`, elementwise.
3350	#[inline(always)]
3351	pub fn convert_i8x32_to_u8x32(self, a: i8x32) -> u8x32 {
3352		cast!(a)
3353	}
3354
3355	/// Converts a `u16x16` to `i16x16`, elementwise.
3356	#[inline(always)]
3357	pub fn convert_u16x16_to_i16x16(self, a: u16x16) -> i16x16 {
3358		cast!(a)
3359	}
3360
3361	/// Converts a `u16x8` to `i32x8`, elementwise.
3362	#[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	/// Converts a `u16x8` to `i64x4`, elementwise, while truncating the extra elements.
3368	#[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	/// Converts a `u16x8` to `u32x8`, elementwise.
3374	#[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	/// Converts a `u16x8` to `u64x4`, elementwise, while truncating the extra elements.
3380	#[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	/// Converts a `u32x4` to `i64x4`, elementwise.
3386	#[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	/// Converts a `u32x4` to `u64x4`, elementwise.
3392	#[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	/// Converts a `u32x8` to `i32x8`, elementwise.
3398	#[inline(always)]
3399	pub fn convert_u32x8_to_i32x8(self, a: u32x8) -> i32x8 {
3400		cast!(a)
3401	}
3402
3403	/// Converts a `u8x16` to `i16x16`, elementwise.
3404	#[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	/// Converts a `u8x16` to `i32x8`, elementwise, while truncating the extra elements.
3410	#[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	/// Converts a `u8x16` to `i64x4`, elementwise, while truncating the extra elements.
3416	#[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	/// Converts a `u8x16` to `u16x16`, elementwise.
3422	#[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	/// Converts a `u8x16` to `u32x8`, elementwise, while truncating the extra elements.
3428	#[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	/// Converts a `u8x16` to `u64x4`, elementwise, while truncating the extra elements.
3434	#[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	/// Converts a `u8x32` to `i8x32`, elementwise.
3440	#[inline(always)]
3441	pub fn convert_u8x32_to_i8x32(self, a: u8x32) -> i8x32 {
3442		cast!(a)
3443	}
3444
3445	/// See [_mm_hadds_epi16].
3446	///
3447	/// [_mm_hadds_epi16]: core::arch::x86_64::_mm_hadds_epi16
3448	#[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	/// See [_mm_hsubs_epi16].
3454	///
3455	/// [_mm_hsubs_epi16]: core::arch::x86_64::_mm_hsubs_epi16
3456	#[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	/// Checks if the elements in each lane of `a` are NaN.
3462	#[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	/// Checks if the elements in each lane of `a` are NaN.
3468	#[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	/// Checks if the elements in each lane of `a` are not NaN.
3474	#[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	/// Checks if the elements in each lane of `a` are not NaN.
3480	#[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	/// Multiplies the elements in each lane of `a` and `b`, and adds the results to each lane of
3486	/// `c`.
3487	#[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	/// Multiplies the elements in each lane of `a` and `b`, and adds the results to each lane of
3493	/// `c`.
3494	#[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	/// Multiplies the elements in each lane of `a` and `b`, and adds the results to each lane of
3500	/// `c`.
3501	#[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	/// Multiplies the elements in each lane of `a` and `b`, and adds the results to each lane of
3507	/// `c`.
3508	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively adds/subtracts 'c'
3514	/// to/from the results.
3515	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively adds/subtracts 'c'
3521	/// to/from the results.
3522	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively adds/subtracts 'c'
3528	/// to/from the results.
3529	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively adds/subtracts 'c'
3535	/// to/from the results.
3536	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3542	/// the results.
3543	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3549	/// the results.
3550	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3556	/// the results.
3557	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3563	/// the results.
3564	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively subtracts/adds 'c'
3570	/// to/from the results.
3571	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively subtracts/adds 'c'
3577	/// to/from the results.
3578	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively subtracts/adds 'c'
3584	/// to/from the results.
3585	#[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	/// Multiplies the elements in each lane of `a` and `b`, and alternatively subtracts/adds 'c'
3591	/// to/from the results.
3592	#[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	/// See [_mm256_maddubs_epi16].
3598	///
3599	/// [_mm256_maddubs_epi16]: core::arch::x86_64::_mm256_maddubs_epi16
3600	#[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	/// See [_mm256_madd_epi16].
3606	///
3607	/// [_mm256_madd_epi16]: core::arch::x86_64::_mm256_madd_epi16
3608	#[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	/// See [_mm256_mpsadbw_epu8].
3614	///
3615	/// [_mm256_mpsadbw_epu8]: core::arch::x86_64::_mm256_mpsadbw_epu8
3616	#[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	/// Multiplies the elements in each lane of `a` and `b`, negates the results, and adds them to
3626	/// each lane of `c`.
3627	#[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	/// Multiplies the elements in each lane of `a` and `b`, negates the results, and adds them to
3633	/// each lane of `c`.
3634	#[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	/// Multiplies the elements in each lane of `a` and `b`, negates the results, and adds them to
3640	/// each lane of `c`.
3641	#[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	/// Multiplies the elements in each lane of `a` and `b`, negates the results, and adds them to
3647	/// each lane of `c`.
3648	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3654	/// the negation of the results.
3655	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3661	/// the negation of the results.
3662	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3668	/// the negation of the results.
3669	#[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	/// Multiplies the elements in each lane of `a` and `b`, and subtracts each lane of `c` from
3675	/// the negation of the results.
3676	#[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	/// Returns `!a` for each bit in a.
3682	#[inline(always)]
3683	pub fn not_i16x16(self, a: i16x16) -> i16x16 {
3684		self.xor_i16x16(a, self.splat_i16x16(!0))
3685	}
3686
3687	/// Returns `!a` for each bit in a.
3688	#[inline(always)]
3689	pub fn not_i32x8(self, a: i32x8) -> i32x8 {
3690		self.xor_i32x8(a, self.splat_i32x8(!0))
3691	}
3692
3693	/// Returns `!a` for each bit in a.
3694	#[inline(always)]
3695	pub fn not_i64x4(self, a: i64x4) -> i64x4 {
3696		self.xor_i64x4(a, self.splat_i64x4(!0))
3697	}
3698
3699	/// Returns `!a` for each bit in a.
3700	#[inline(always)]
3701	pub fn not_i8x32(self, a: i8x32) -> i8x32 {
3702		self.xor_i8x32(a, self.splat_i8x32(!0))
3703	}
3704
3705	/// Returns `!a` for each bit in a.
3706	#[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	/// Returns `!a` for each bit in a.
3712	#[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	/// Returns `!a` for each bit in a.
3718	#[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	/// Returns `!a` for each bit in a.
3724	#[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	/// Returns `!a` for each bit in a.
3730	#[inline(always)]
3731	pub fn not_u16x16(self, a: u16x16) -> u16x16 {
3732		self.xor_u16x16(a, self.splat_u16x16(!0))
3733	}
3734
3735	/// Returns `!a` for each bit in a.
3736	#[inline(always)]
3737	pub fn not_u32x8(self, a: u32x8) -> u32x8 {
3738		self.xor_u32x8(a, self.splat_u32x8(!0))
3739	}
3740
3741	/// Returns `!a` for each bit in a.
3742	#[inline(always)]
3743	pub fn not_u64x4(self, a: u64x4) -> u64x4 {
3744		self.xor_u64x4(a, self.splat_u64x4(!0))
3745	}
3746
3747	/// Returns `!a` for each bit in a.
3748	#[inline(always)]
3749	pub fn not_u8x32(self, a: u8x32) -> u8x32 {
3750		self.xor_u8x32(a, self.splat_u8x32(!0))
3751	}
3752
3753	/// See [_mm256_packs_epi16].
3754	///
3755	/// [_mm256_packs_epi16]: core::arch::x86_64::_mm256_packs_epi16
3756	#[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	/// See [_mm256_packs_epi32].
3762	///
3763	/// [_mm256_packs_epi32]: core::arch::x86_64::_mm256_packs_epi32
3764	#[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	/// See [_mm256_packus_epi16].
3770	///
3771	/// [_mm256_packus_epi16]: core::arch::x86_64::_mm256_packus_epi16
3772	#[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	/// See [_mm256_packus_epi32].
3778	///
3779	/// [_mm256_packus_epi32]: core::arch::x86_64::_mm256_packus_epi32
3780	#[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	/// Rounds the elements of each lane of `a` to the nearest integer. If two values are equally
3786	/// close, the even value is returned.
3787	#[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	/// Rounds the elements of each lane of `a` to the nearest integer. If two values are equally
3794	/// close, the even value is returned.
3795	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3802	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3803	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3812	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3813	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3819	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3820	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3826	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3827	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3833	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3834	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3843	/// bit in the mask is set, otherwise selecting elements from `if_false`.
3844	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3853	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3854	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3863	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3864	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3873	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3874	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3880	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3881	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3887	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3888	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3894	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3895	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3901	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3902	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3911	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3912	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3921	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3922	#[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	/// Combines `if_true` and `if_false`, selecting elements from `if_true` if the corresponding
3931	/// mask in `mask` is set, otherwise selecting elements from `if_false`.
3932	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3941	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3942	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3948	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3949	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3955	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3956	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3962	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3963	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3969	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3970	#[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	/// Shift the bits of each lane of `a` to the left by `AMOUNT`, while shifting in zeros.
3976	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3977	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
3983	/// `amount`, while shifting in zeros.
3984	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3985	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
3991	/// `amount`, while shifting in zeros.
3992	/// Shifting by a value greater than the bit width of the type sets the result to zero.
3993	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
3999	/// `amount`, while shifting in zeros.
4000	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4001	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
4007	/// `amount`, while shifting in zeros.
4008	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4009	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
4015	/// `amount`, while shifting in zeros.
4016	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4017	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
4023	/// `amount`, while shifting in zeros.
4024	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4025	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
4031	/// `amount`, while shifting in zeros.
4032	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4033	#[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	/// Shift the bits of each lane of `a` to the left by the element in the corresponding lane in
4039	/// `amount`, while shifting in zeros.
4040	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4041	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4047	/// shifting in zeros.
4048	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4049	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4055	/// shifting in zeros.
4056	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4057	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4063	/// shifting in zeros.
4064	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4065	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4071	/// shifting in zeros.
4072	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4073	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4079	/// shifting in zeros.
4080	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4081	#[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	/// Shift the bits of each lane of `a` to the left by the first element in `amount`, while
4087	/// shifting in zeros.
4088	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4089	#[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	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in sign bits.
4095	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4096	/// sign bit is not set, and to `-1` if the sign bit is set.
4097	#[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	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in sign bits.
4103	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4104	/// sign bit is not set, and to `-1` if the sign bit is set.
4105	#[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	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
4111	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4112	#[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	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
4118	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4119	#[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	/// Shift the bits of each lane of `a` to the right by `AMOUNT`, while shifting in zeros.
4125	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4126	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4132	/// `amount`, while shifting in sign bits.
4133	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4134	/// sign bit is not set, and to `-1` if the sign bit is set.
4135	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4141	/// `amount`, while shifting in sign bits.
4142	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4143	/// sign bit is not set, and to `-1` if the sign bit is set.
4144	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4150	/// `amount`, while shifting in zeros.
4151	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4152	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4158	/// `amount`, while shifting in zeros.
4159	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4160	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4166	/// `amount`, while shifting in zeros.
4167	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4168	#[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	/// Shift the bits of each lane of `a` to the right by the element in the corresponding lane in
4174	/// `amount`, while shifting in zeros.
4175	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4176	#[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	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
4182	/// shifting in zeros.
4183	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4184	/// sign bit is not set, and to `-1` if the sign bit is set.
4185	#[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	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
4191	/// shifting in zeros.
4192	/// Shifting by a value greater than the bit width of the type sets the result to zero if the
4193	/// sign bit is not set, and to `-1` if the sign bit is set.
4194	#[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	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
4200	/// shifting in zeros.
4201	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4202	#[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	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
4208	/// shifting in zeros.
4209	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4210	#[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	/// Shift the bits of each lane of `a` to the right by the first element in `amount`, while
4216	/// shifting in zeros.
4217	/// Shifting by a value greater than the bit width of the type sets the result to zero.
4218	#[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	/// Returns a SIMD vector with all lanes set to the given value.
4224	#[inline(always)]
4225	pub fn splat_f32x8(self, value: f32) -> f32x8 {
4226		cast!(self.avx._mm256_set1_ps(value))
4227	}
4228
4229	/// Returns a SIMD vector with all lanes set to the given value.
4230	#[inline(always)]
4231	pub fn splat_f64x4(self, value: f64) -> f64x4 {
4232		cast!(self.avx._mm256_set1_pd(value))
4233	}
4234
4235	/// Returns a SIMD vector with all lanes set to the given value.
4236	#[inline(always)]
4237	pub fn splat_i16x16(self, value: i16) -> i16x16 {
4238		cast!(self.avx._mm256_set1_epi16(value))
4239	}
4240
4241	/// Returns a SIMD vector with all lanes set to the given value.
4242	#[inline(always)]
4243	pub fn splat_i32x8(self, value: i32) -> i32x8 {
4244		cast!(self.avx._mm256_set1_epi32(value))
4245	}
4246
4247	/// Returns a SIMD vector with all lanes set to the given value.
4248	#[inline(always)]
4249	pub fn splat_i64x4(self, value: i64) -> i64x4 {
4250		cast!(self.avx._mm256_set1_epi64x(value))
4251	}
4252
4253	/// Returns a SIMD vector with all lanes set to the given value.
4254	#[inline(always)]
4255	pub fn splat_i8x32(self, value: i8) -> i8x32 {
4256		cast!(self.avx._mm256_set1_epi8(value))
4257	}
4258
4259	/// Returns a SIMD vector with all lanes set to the given value.
4260	#[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	/// Returns a SIMD vector with all lanes set to the given value.
4266	#[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	/// Returns a SIMD vector with all lanes set to the given value.
4272	#[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	/// Returns a SIMD vector with all lanes set to the given value.
4278	#[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	/// Returns a SIMD vector with all lanes set to the given value.
4284	#[inline(always)]
4285	pub fn splat_u16x16(self, value: u16) -> u16x16 {
4286		cast!(self.avx._mm256_set1_epi16(value as i16))
4287	}
4288
4289	/// Returns a SIMD vector with all lanes set to the given value.
4290	#[inline(always)]
4291	pub fn splat_u32x8(self, value: u32) -> u32x8 {
4292		cast!(self.avx._mm256_set1_epi32(value as i32))
4293	}
4294
4295	/// Returns a SIMD vector with all lanes set to the given value.
4296	#[inline(always)]
4297	pub fn splat_u64x4(self, value: u64) -> u64x4 {
4298		cast!(self.avx._mm256_set1_epi64x(value as i64))
4299	}
4300
4301	/// Returns a SIMD vector with all lanes set to the given value.
4302	#[inline(always)]
4303	pub fn splat_u8x32(self, value: u8) -> u8x32 {
4304		cast!(self.avx._mm256_set1_epi8(value as i8))
4305	}
4306
4307	/// Computes the square roots of the elements of each lane of `a`.
4308	#[inline(always)]
4309	pub fn sqrt_f32x8(self, a: f32x8) -> f32x8 {
4310		cast!(self.avx._mm256_sqrt_ps(cast!(a)))
4311	}
4312
4313	/// Computes the square roots of the elements of each lane of `a`.
4314	#[inline(always)]
4315	pub fn sqrt_f64x4(self, a: f64x4) -> f64x4 {
4316		cast!(self.avx._mm256_sqrt_pd(cast!(a)))
4317	}
4318
4319	/// See [_mm256_sad_epu8].
4320	///
4321	/// [_mm256_sad_epu8]: core::arch::x86_64::_mm256_sad_epu8
4322	#[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	/// Rounds the elements of each lane of `a` to the nearest integer towards zero.
4328	#[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	/// Rounds the elements of each lane of `a` to the nearest integer towards zero.
4335	#[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	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
4342	/// high bits of the result.
4343	#[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	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
4352	/// high bits of the result.
4353	#[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		// a0b0_lo a0b0_hi a2b2_lo a2b2_hi
4360		let ab_evens = self.avx2._mm256_mul_epi32(a, b);
4361		// a1b1_lo a1b1_hi a3b3_lo a3b3_hi
4362		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			// a0b0_lo xxxxxxx a2b2_lo xxxxxxx
4369			ab_evens,
4370			// xxxxxxx a1b1_lo xxxxxxx a3b3_lo
4371			avx2._mm256_slli_epi64::<32>(ab_odds),
4372		);
4373		let ab_hi = self.avx2._mm256_blend_epi32::<0b10101010>(
4374			// a0b0_hi xxxxxxx a2b2_hi xxxxxxx
4375			avx2._mm256_srli_epi64::<32>(ab_evens),
4376			// xxxxxxx a1b1_hi xxxxxxx a3b3_hi
4377			ab_odds,
4378		);
4379
4380		(cast!(ab_lo), cast!(ab_hi))
4381	}
4382
4383	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
4384	/// high bits of the result.
4385	#[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	/// Multiplies the elements of each lane of `a` and `b`, and returns separately the low and
4394	/// high bits of the result.
4395	#[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		// a0b0_lo a0b0_hi a2b2_lo a2b2_hi
4402		let ab_evens = avx2._mm256_mul_epu32(a, b);
4403		// a1b1_lo a1b1_hi a3b3_lo a3b3_hi
4404		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			// a0b0_lo xxxxxxx a2b2_lo xxxxxxx
4411			ab_evens,
4412			// xxxxxxx a1b1_lo xxxxxxx a3b3_lo
4413			avx2._mm256_slli_epi64::<32>(ab_odds),
4414		);
4415		let ab_hi = self.avx2._mm256_blend_epi32::<0b10101010>(
4416			// a0b0_hi xxxxxxx a2b2_hi xxxxxxx
4417			avx2._mm256_srli_epi64::<32>(ab_evens),
4418			// xxxxxxx a1b1_hi xxxxxxx a3b3_hi
4419			ab_odds,
4420		);
4421
4422		(cast!(ab_lo), cast!(ab_hi))
4423	}
4424}