Skip to main content

pulp/
lib.rs

1//! `pulp` is a safe abstraction over SIMD instructions, that allows you to write a function once
2//! and dispatch to equivalent vectorized versions based on the features detected at runtime.
3//!
4//! # Autovectorization example
5//!
6//! ```
7//! use pulp::Arch;
8//!
9//! let mut v = (0..1000).map(|i| i as f64).collect::<Vec<_>>();
10//! let arch = Arch::new();
11//!
12//! arch.dispatch(|| {
13//! 	for x in &mut v {
14//! 		*x *= 2.0;
15//! 	}
16//! });
17//!
18//! for (i, x) in v.into_iter().enumerate() {
19//! 	assert_eq!(x, 2.0 * i as f64);
20//! }
21//! ```
22//!
23//! # Manual vectorization example
24//!
25//! ```
26//! use pulp::{Arch, Simd, WithSimd};
27//!
28//! struct TimesThree<'a>(&'a mut [f64]);
29//! impl<'a> WithSimd for TimesThree<'a> {
30//! 	type Output = ();
31//!
32//! 	#[inline(always)]
33//! 	fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
34//! 		let v = self.0;
35//! 		let (head, tail) = S::as_mut_simd_f64s(v);
36//!
37//! 		let three = simd.splat_f64s(3.0);
38//! 		for x in head {
39//! 			*x = simd.mul_f64s(three, *x);
40//! 		}
41//!
42//! 		for x in tail {
43//! 			*x = *x * 3.0;
44//! 		}
45//! 	}
46//! }
47//!
48//! let mut v = (0..1000).map(|i| i as f64).collect::<Vec<_>>();
49//! let arch = Arch::new();
50//!
51//! arch.dispatch(TimesThree(&mut v));
52//!
53//! for (i, x) in v.into_iter().enumerate() {
54//! 	assert_eq!(x, 3.0 * i as f64);
55//! }
56//! ```
57
58// FIXME: replace x86 non-ieee min/max functions to propagate nans instead
59
60#![allow(
61	non_camel_case_types,
62	unknown_lints,
63	clippy::zero_prefixed_literal,
64	clippy::identity_op,
65	clippy::too_many_arguments,
66	clippy::type_complexity,
67	clippy::missing_transmute_annotations,
68	clippy::tabs_in_doc_comments,
69	clippy::modulo_one,
70	clippy::useless_transmute,
71	clippy::not_unsafe_ptr_arg_deref,
72	clippy::manual_is_multiple_of
73)]
74#![cfg_attr(
75	all(feature = "nightly", any(target_arch = "aarch64")),
76	feature(stdarch_neon_i8mm),
77	feature(stdarch_neon_sm4),
78	feature(stdarch_neon_ftts),
79	feature(stdarch_neon_fcma),
80	feature(stdarch_neon_dotprod)
81)]
82#![cfg_attr(not(feature = "std"), no_std)]
83#![cfg_attr(docsrs, feature(doc_cfg))]
84
85macro_rules! match_cfg {
86    (item, match cfg!() {
87        $(
88            const { $i_meta:meta } => { $( $i_tokens:tt )* },
89        )*
90        $(_ => { $( $e_tokens:tt )* },)?
91    }) => {
92        $crate::match_cfg! {
93            @__items () ;
94            $(
95                (( $i_meta ) ( $( $i_tokens )* )) ,
96            )*
97            $((() ( $( $e_tokens )* )),)?
98        }
99    };
100
101    (match cfg!() {
102        $(
103            const { $i_meta:meta } => $i_expr: expr,
104        )*
105        $(_ => $e_expr: expr,)?
106    }) => {
107        $crate::match_cfg! {
108            @ __result @ __exprs ();
109            $(
110                (( $i_meta ) ( $i_expr  )) ,
111            )*
112            $((() ( $e_expr  )),)?
113        }
114    };
115
116    // Internal and recursive macro to emit all the items
117    //
118    // Collects all the previous cfgs in a list at the beginning, so they can be
119    // negated. After the semicolon are all the remaining items.
120    (@__items ( $( $_:meta , )* ) ; ) => {};
121    (
122        @__items ( $( $no:meta , )* ) ;
123        (( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
124        $( $rest:tt , )*
125    ) => {
126        // Emit all items within one block, applying an appropriate [cfg]. The
127        // [cfg] will require all `$yes` matchers specified and must also negate
128        // all previous matchers.
129        #[cfg(all(
130            $( $yes , )?
131            not(any( $( $no ),* ))
132        ))]
133        $crate::match_cfg! { @__identity $( $tokens )* }
134
135        // Recurse to emit all other items in `$rest`, and when we do so add all
136        // our `$yes` matchers to the list of `$no` matchers as future emissions
137        // will have to negate everything we just matched as well.
138        $crate::match_cfg! {
139            @__items ( $( $no , )* $( $yes , )? ) ;
140            $( $rest , )*
141        }
142    };
143
144    // Internal and recursive macro to emit all the exprs
145    //
146    // Collects all the previous cfgs in a list at the beginning, so they can be
147    // negated. After the semicolon are all the remaining exprs.
148    (@ $ret: ident @ __exprs ( $( $_:meta , )* ) ; ) => {
149    	$ret
150    };
151
152    (
153        @ $ret: ident @__exprs ( $( $no:meta , )* ) ;
154        (( $( $yes:meta )? ) ( $( $tokens:tt )* )) ,
155        $( $rest:tt , )*
156    ) => {{
157        // Emit all exprs within one block, applying an appropriate [cfg]. The
158        // [cfg] will require all `$yes` matchers specified and must also negate
159        // all previous matchers.
160        #[cfg(all(
161            $( $yes , )?
162            not(any( $( $no ),* ))
163        ))]
164        let $ret = $crate::match_cfg! { @__identity $( $tokens )* };
165
166        // // Recurse to emit all other exprs in `$rest`, and when we do so add all
167        // // our `$yes` matchers to the list of `$no` matchers as future emissions
168        // // will have to negate everything we just matched as well.
169        $crate::match_cfg! {
170            @ $ret @ __exprs ( $( $no , )* $( $yes , )? ) ;
171            $( $rest , )*
172        }
173    }};
174
175    // Internal macro to make __apply work out right for different match types,
176    // because of how macros match/expand stuff.
177    (@__identity $( $tokens:tt )* ) => {
178        $( $tokens )*
179    };
180}
181
182const MAX_REGISTER_BYTES: usize = 256;
183
184use match_cfg;
185
186/// Safe transmute macro.
187///
188/// This function asserts at compile time that the two types have the same size.
189#[macro_export]
190macro_rules! cast {
191	($val: expr $(,)?) => {{
192		let __val = $val;
193		if const { false } {
194			// checks type constraints
195			$crate::cast(__val)
196		} else {
197			#[allow(
198				unused_unsafe,
199				unnecessary_transmutes,
200				clippy::missing_transmute_annotations
201			)]
202			unsafe {
203				::core::mem::transmute(__val)
204			}
205		}
206	}};
207}
208
209use bytemuck::{AnyBitPattern, CheckedBitPattern, NoUninit, Pod, Zeroable, checked};
210use core::fmt::Debug;
211use core::marker::PhantomData;
212use core::mem::MaybeUninit;
213use core::ops::*;
214use core::slice::{from_raw_parts, from_raw_parts_mut};
215use num_complex::Complex;
216use paste::paste;
217use seal::Seal;
218
219/// Requires the first non-lifetime generic parameter, as well as the function's
220/// first input parameter to be the SIMD type.
221/// Also currently requires that all the lifetimes be explicitly specified.
222#[cfg(feature = "macro")]
223#[cfg_attr(docsrs, doc(cfg(feature = "macro")))]
224pub use pulp_macro::with_simd;
225
226pub use bytemuck;
227pub use num_complex;
228
229pub type c32 = Complex<f32>;
230pub type c64 = Complex<f64>;
231
232#[derive(Copy, Clone)]
233#[repr(transparent)]
234struct DebugCplx<T>(T);
235
236unsafe impl<T: Zeroable> Zeroable for DebugCplx<T> {}
237unsafe impl<T: Pod> Pod for DebugCplx<T> {}
238
239impl Debug for DebugCplx<c32> {
240	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
241		let c32 { re, im } = self.0;
242		re.fmt(f)?;
243
244		let sign = if im.is_sign_positive() { " + " } else { " - " };
245		f.write_str(sign)?;
246
247		let im = f32::from_bits(im.to_bits() & (u32::MAX >> 1));
248		im.abs().fmt(f)?;
249
250		f.write_str("i")?;
251
252		Ok(())
253	}
254}
255
256impl Debug for DebugCplx<c64> {
257	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
258		let c64 { re, im } = self.0;
259		re.fmt(f)?;
260
261		let sign = if im.is_sign_positive() { " + " } else { " - " };
262		f.write_str(sign)?;
263
264		let im = f64::from_bits(im.to_bits() & (u64::MAX >> 1));
265		im.abs().fmt(f)?;
266
267		f.write_str("i")?;
268
269		Ok(())
270	}
271}
272
273match_cfg!(
274	item,
275	match cfg!() {
276		const { any(target_arch = "x86_64") } => {
277			#[derive(Debug, Copy, Clone)]
278			pub struct MemMask<T> {
279				mask: T,
280				load: Option<unsafe extern "C" fn()>,
281				store: Option<unsafe extern "C" fn()>,
282			}
283
284			impl<T> MemMask<T> {
285				#[inline]
286				pub fn new(mask: T) -> Self {
287					Self {
288						mask,
289						load: None,
290						store: None,
291					}
292				}
293			}
294
295			impl<T> From<T> for MemMask<T> {
296				#[inline]
297				fn from(value: T) -> Self {
298					Self {
299						mask: value,
300						load: None,
301						store: None,
302					}
303				}
304			}
305		},
306
307		_ => {
308			#[derive(Debug, Copy, Clone)]
309			pub struct MemMask<T> {
310				mask: T,
311			}
312
313			impl<T> MemMask<T> {
314				#[inline]
315				pub fn new(mask: T) -> Self {
316					Self { mask }
317				}
318			}
319
320			impl<T> From<T> for MemMask<T> {
321				#[inline]
322				fn from(value: T) -> Self {
323					Self { mask: value }
324				}
325			}
326		},
327	}
328);
329
330impl<T: Copy> MemMask<T> {
331	#[inline]
332	pub fn mask(self) -> T {
333		self.mask
334	}
335}
336
337mod seal {
338	pub trait Seal {}
339}
340
341pub trait NullaryFnOnce {
342	type Output;
343
344	fn call(self) -> Self::Output;
345}
346
347impl<R, F: FnOnce() -> R> NullaryFnOnce for F {
348	type Output = R;
349
350	#[inline(always)]
351	fn call(self) -> Self::Output {
352		self()
353	}
354}
355
356pub trait WithSimd {
357	type Output;
358
359	fn with_simd<S: Simd>(self, simd: S) -> Self::Output;
360}
361
362impl<F: NullaryFnOnce> WithSimd for F {
363	type Output = F::Output;
364
365	#[inline(always)]
366	fn with_simd<S: Simd>(self, simd: S) -> Self::Output {
367		let _simd = &simd;
368		self.call()
369	}
370}
371
372#[inline(always)]
373fn fma_f32(a: f32, b: f32, c: f32) -> f32 {
374	match_cfg!(match cfg!() {
375		const { feature = "std" } => f32::mul_add(a, b, c),
376		_ => libm::fmaf(a, b, c),
377	})
378}
379
380#[inline(always)]
381fn fma_f64(a: f64, b: f64, c: f64) -> f64 {
382	match_cfg!(match cfg!() {
383		const { feature = "std" } => f64::mul_add(a, b, c),
384		_ => libm::fma(a, b, c),
385	})
386}
387
388#[inline(always)]
389fn sqrt_f32(a: f32) -> f32 {
390	match_cfg!(match cfg!() {
391		const { feature = "std" } => f32::sqrt(a),
392		_ => libm::sqrtf(a),
393	})
394}
395
396#[inline(always)]
397fn sqrt_f64(a: f64) -> f64 {
398	match_cfg!(match cfg!() {
399		const { feature = "std" } => f64::sqrt(a, ),
400		_ => libm::sqrt(a),
401	})
402}
403
404// a0,0 ... a0,m-1
405// ...
406// an-1,0 ... an-1,m-1
407#[inline(always)]
408unsafe fn interleave_fallback<Unit: Pod, Reg: Pod, AosReg>(x: AosReg) -> AosReg {
409	assert!(core::mem::size_of::<AosReg>() % core::mem::size_of::<Reg>() == 0);
410	assert!(core::mem::size_of::<Reg>() % core::mem::size_of::<Unit>() == 0);
411	assert!(!core::mem::needs_drop::<AosReg>());
412
413	if const { core::mem::size_of::<AosReg>() == core::mem::size_of::<Reg>() } {
414		x
415	} else {
416		let mut y = core::ptr::read(&x);
417
418		let n = const { core::mem::size_of::<AosReg>() / core::mem::size_of::<Reg>() };
419		let m = const { core::mem::size_of::<Reg>() / core::mem::size_of::<Unit>() };
420
421		unsafe {
422			let y = (&mut y) as *mut _ as *mut Unit;
423			let x = (&x) as *const _ as *const Unit;
424			for j in 0..m {
425				for i in 0..n {
426					*y.add(i + n * j) = *x.add(j + i * m);
427				}
428			}
429		}
430
431		y
432	}
433}
434
435#[inline(always)]
436unsafe fn deinterleave_fallback<Unit: Pod, Reg: Pod, SoaReg>(y: SoaReg) -> SoaReg {
437	assert!(core::mem::size_of::<SoaReg>() % core::mem::size_of::<Reg>() == 0);
438	assert!(core::mem::size_of::<Reg>() % core::mem::size_of::<Unit>() == 0);
439	assert!(!core::mem::needs_drop::<SoaReg>());
440
441	if const { core::mem::size_of::<SoaReg>() == core::mem::size_of::<Reg>() } {
442		y
443	} else {
444		let mut x = core::ptr::read(&y);
445
446		let n = const { core::mem::size_of::<SoaReg>() / core::mem::size_of::<Reg>() };
447		let m = const { core::mem::size_of::<Reg>() / core::mem::size_of::<Unit>() };
448
449		unsafe {
450			let y = (&y) as *const _ as *const Unit;
451			let x = (&mut x) as *mut _ as *mut Unit;
452			for j in 0..m {
453				for i in 0..n {
454					*x.add(j + i * m) = *y.add(i + n * j);
455				}
456			}
457		}
458
459		x
460	}
461}
462
463macro_rules! define_binop {
464	($func: ident, $ty: ident, $out: ident) => {
465		paste! {
466			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>];
467		}
468	};
469}
470
471macro_rules! define_binop_all {
472	($func: ident, $($ty: ident),*) => {
473		$(define_binop!($func, $ty, $ty);)*
474	};
475	($func: ident, $($ty: ident => $out: ident),*) => {
476		$(define_binop!($func, $ty, $out);)*
477	};
478}
479
480macro_rules! transmute_binop {
481	($func: ident, $ty: ident, $to: ident) => {
482		paste! {
483			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$ty s>] {
484				self.[<transmute_ $ty s_ $to s>](
485					self.[<$func _ $to s>](self.[<transmute_ $to s_ $ty s>](a), self.[<transmute_ $to s_ $ty s>](b)),
486				)
487			}
488		}
489	};
490	($func: ident, $($ty: ident => $to: ident),*) => {
491		$(transmute_binop!($func, $ty, $to);)*
492	};
493}
494
495macro_rules! define_unop {
496	($func: ident, $ty: ident, $out: ident) => {
497		paste! {
498			fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$out s>];
499		}
500	};
501}
502
503macro_rules! define_unop_all {
504	($func: ident, $($ty: ident),*) => {
505		$(define_unop!($func, $ty, $ty);)*
506	};
507	($func: ident, $($ty: ident => $out: ident),*) => {
508		$(define_unop!($func, $ty, $out);)*
509	};
510}
511
512macro_rules! transmute_unop {
513	($func: ident, $ty: ident, $to: ident) => {
514		paste! {
515			fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$ty s>] {
516				self.[<transmute_ $ty s_ $to s>](
517					self.[<$func _ $to s>](self.[<transmute_ $to s_ $ty s>](a)),
518				)
519			}
520		}
521	};
522	($func: ident, $($ty: ident => $to: ident),*) => {
523		$(transmute_unop!($func, $ty, $to);)*
524	};
525}
526
527macro_rules! transmute_cmp {
528	($func: ident, $ty: ident, $to: ident, $out: ident) => {
529		paste! {
530			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
531				self.[<$func _ $to s>](self.[<transmute_ $to s_ $ty s>](a), self.[<transmute_ $to s_ $ty s>](b))
532			}
533		}
534	};
535	($func: ident, $($ty: ident => $to: ident => $out: ident),*) => {
536		$(transmute_cmp!($func, $ty, $to, $out);)*
537	};
538}
539
540macro_rules! define_splat {
541	($ty: ty) => {
542		paste! {
543			fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>];
544		}
545	};
546	($($ty: ident),*) => {
547		$(define_splat!($ty);)*
548	};
549}
550
551macro_rules! split_slice {
552	($ty: ident) => {
553		paste! {
554			#[inline(always)]
555			fn [<as_mut_rsimd_ $ty s>](slice: &mut [$ty]) -> (&mut [$ty], &mut [Self::[<$ty s>]]) {
556				unsafe { rsplit_mut_slice(slice) }
557			}
558			#[inline(always)]
559			fn [<as_rsimd_ $ty s>](slice: &[$ty]) -> (&[$ty], &[Self::[<$ty s>]]) {
560				unsafe { rsplit_slice(slice) }
561			}
562			#[inline(always)]
563			fn [<as_mut_simd_ $ty s>](slice: &mut [$ty]) -> (&mut [Self::[<$ty s>]], &mut [$ty]) {
564				unsafe { split_mut_slice(slice) }
565			}
566			#[inline(always)]
567			fn [<as_simd_ $ty s>](slice: &[$ty]) -> (&[Self::[<$ty s>]], &[$ty]) {
568				unsafe { split_slice(slice) }
569			}
570			#[inline(always)]
571			fn [<as_uninit_mut_rsimd_ $ty s>](
572				slice: &mut [MaybeUninit<$ty>],
573			) -> (&mut [MaybeUninit<$ty>], &mut [MaybeUninit<Self::[<$ty s>]>]) {
574				unsafe { rsplit_mut_slice(slice) }
575			}
576			#[inline(always)]
577			fn [<as_uninit_mut_simd_ $ty s>](
578				slice: &mut [MaybeUninit<$ty>],
579			) -> (&mut [MaybeUninit<Self::[<$ty s>]>], &mut [MaybeUninit<$ty>]) {
580				unsafe { split_mut_slice(slice) }
581			}
582		}
583	};
584	($($ty: ident),*) => {
585		$(split_slice!($ty);)*
586	};
587}
588
589/// Types that allow \[de\]interleaving.
590///
591/// # Safety
592/// Instances of this type passed to simd \[de\]interleave functions must be `Pod`.
593pub unsafe trait Interleave {}
594unsafe impl<T: Pod> Interleave for T {}
595
596pub trait Simd: Seal + Debug + Copy + Send + Sync + 'static {
597	const IS_SCALAR: bool = false;
598
599	const M64_LANES: usize = core::mem::size_of::<Self::m64s>() / core::mem::size_of::<m64>();
600	const U64_LANES: usize = core::mem::size_of::<Self::u64s>() / core::mem::size_of::<u64>();
601	const I64_LANES: usize = core::mem::size_of::<Self::i64s>() / core::mem::size_of::<i64>();
602	const F64_LANES: usize = core::mem::size_of::<Self::f64s>() / core::mem::size_of::<f64>();
603	const C64_LANES: usize = core::mem::size_of::<Self::c64s>() / core::mem::size_of::<c64>();
604
605	const M32_LANES: usize = core::mem::size_of::<Self::m32s>() / core::mem::size_of::<m32>();
606	const U32_LANES: usize = core::mem::size_of::<Self::u32s>() / core::mem::size_of::<u32>();
607	const I32_LANES: usize = core::mem::size_of::<Self::i32s>() / core::mem::size_of::<i32>();
608	const F32_LANES: usize = core::mem::size_of::<Self::f32s>() / core::mem::size_of::<f32>();
609	const C32_LANES: usize = core::mem::size_of::<Self::c32s>() / core::mem::size_of::<c32>();
610
611	const M16_LANES: usize = core::mem::size_of::<Self::m16s>() / core::mem::size_of::<m16>();
612	const U16_LANES: usize = core::mem::size_of::<Self::u16s>() / core::mem::size_of::<u16>();
613	const I16_LANES: usize = core::mem::size_of::<Self::i16s>() / core::mem::size_of::<i16>();
614
615	const M8_LANES: usize = core::mem::size_of::<Self::m8s>() / core::mem::size_of::<m8>();
616	const U8_LANES: usize = core::mem::size_of::<Self::u8s>() / core::mem::size_of::<u8>();
617	const I8_LANES: usize = core::mem::size_of::<Self::i8s>() / core::mem::size_of::<i8>();
618
619	const REGISTER_COUNT: usize;
620
621	type m8s: Debug + Copy + Send + Sync + Zeroable + NoUninit + CheckedBitPattern + 'static;
622	type i8s: Debug + Copy + Send + Sync + Pod + 'static;
623	type u8s: Debug + Copy + Send + Sync + Pod + 'static;
624
625	type m16s: Debug + Copy + Send + Sync + Zeroable + NoUninit + CheckedBitPattern + 'static;
626	type i16s: Debug + Copy + Send + Sync + Pod + 'static;
627	type u16s: Debug + Copy + Send + Sync + Pod + 'static;
628
629	type m32s: Debug + Copy + Send + Sync + Zeroable + NoUninit + CheckedBitPattern + 'static;
630	type f32s: Debug + Copy + Send + Sync + Pod + 'static;
631	type c32s: Debug + Copy + Send + Sync + Pod + 'static;
632	type i32s: Debug + Copy + Send + Sync + Pod + 'static;
633	type u32s: Debug + Copy + Send + Sync + Pod + 'static;
634
635	type m64s: Debug + Copy + Send + Sync + Zeroable + NoUninit + CheckedBitPattern + 'static;
636	type f64s: Debug + Copy + Send + Sync + Pod + 'static;
637	type c64s: Debug + Copy + Send + Sync + Pod + 'static;
638	type i64s: Debug + Copy + Send + Sync + Pod + 'static;
639	type u64s: Debug + Copy + Send + Sync + Pod + 'static;
640
641	/// Contains the square of the norm in both the real and imaginary components.
642	fn abs2_c32s(self, a: Self::c32s) -> Self::c32s;
643
644	/// Contains the square of the norm in both the real and imaginary components.
645	fn abs2_c64s(self, a: Self::c64s) -> Self::c64s;
646	#[inline]
647	fn abs_f32s(self, a: Self::f32s) -> Self::f32s {
648		self.and_f32s(self.not_f32s(self.splat_f32s(-0.0)), a)
649	}
650	#[inline]
651	fn abs_f64s(self, a: Self::f64s) -> Self::f64s {
652		self.and_f64s(self.not_f64s(self.splat_f64s(-0.0)), a)
653	}
654	/// Contains the max norm in both the real and imaginary components.
655	fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s;
656	/// Contains the max norm in both the real and imaginary components.
657	fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s;
658
659	define_binop_all!(add, c32, c64, f32, f64, u8, u16, u32, u64);
660	define_binop_all!(
661		sub, c32, c64, f32, f64, u8, i8, u16, i16, u32, i32, u64, i64
662	);
663	define_binop_all!(mul, c32, c64, f32, f64, u16, i16, u32, i32, u64, i64);
664	define_binop_all!(div, f32, f64);
665	define_binop_all!(equal, u8 => m8, u16 => m16, u32 => m32, u64 => m64, c32 => m32, f32 => m32, c64 => m64, f64 => m64);
666	define_binop_all!(greater_than, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
667	define_binop_all!(greater_than_or_equal, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
668	define_binop_all!(less_than_or_equal, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
669	define_binop_all!(less_than, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
670
671	define_binop_all!(and, u8, u16, u32, u64);
672	define_binop_all!(or, u8, u16, u32, u64);
673	define_binop_all!(xor, u8, u16, u32, u64);
674
675	transmute_binop!(and, m8 => u8, i8 => u8, m16 => u16, i16 => u16, m32 => u32, i32 => u32, m64 => u64, i64 => u64, f32 => u32, f64 => u64);
676	transmute_binop!(or, m8 => u8, i8 => u8, m16 => u16, i16 => u16, m32 => u32, i32 => u32, m64 => u64, i64 => u64, f32 => u32, f64 => u64);
677	transmute_binop!(xor, m8 => u8, i8 => u8, m16 => u16, i16 => u16, m32 => u32, i32 => u32, m64 => u64, i64 => u64, f32 => u32, f64 => u64);
678
679	transmute_binop!(add, i8 => u8, i16 => u16, i32 => u32, i64 => u64);
680	transmute_cmp!(equal, m8 => u8 => m8, i8 => u8 => m8, m16 => u16 => m16, i16 => u16 => m16, m32 => u32 => m32, i32 => u32 => m32, m64 => u64 => m64, i64 => u64 => m64);
681
682	define_binop_all!(min, f32, f64, u8, i8, u16, i16, u32, i32, u64, i64);
683	define_binop_all!(max, f32, f64, u8, i8, u16, i16, u32, i32, u64, i64);
684
685	define_unop_all!(neg, c32, c64);
686	define_unop_all!(not, m8, u8, m16, u16, m32, u32, m64, u64);
687
688	transmute_unop!(not, i8 => u8, i16 => u16, i32 => u32, i64 => u64, f32 => u32, f64 => u64);
689
690	split_slice!(u8, i8, u16, i16, u32, i32, u64, i64, c32, f32, c64, f64);
691	define_splat!(u8, i8, u16, i16, u32, i32, u64, i64, c32, f32, c64, f64);
692
693	fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s;
694	fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s;
695
696	fn conj_c32s(self, a: Self::c32s) -> Self::c32s;
697	fn conj_c64s(self, a: Self::c64s) -> Self::c64s;
698	fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
699	fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
700
701	/// Computes `conj(a) * b + c`
702	#[inline]
703	fn conj_mul_add_e_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
704		self.conj_mul_add_c32s(a, b, c)
705	}
706	/// Computes `conj(a) * b + c`
707	#[inline]
708	fn conj_mul_add_e_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
709		self.conj_mul_add_c64s(a, b, c)
710	}
711	fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s;
712
713	fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s;
714	/// Computes `conj(a) * b`
715	#[inline]
716	fn conj_mul_e_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
717		self.conj_mul_c32s(a, b)
718	}
719	/// Computes `conj(a) * b`
720	#[inline]
721	fn conj_mul_e_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
722		self.conj_mul_c64s(a, b)
723	}
724	#[inline(always)]
725	fn deinterleave_shfl_f32s<T: Interleave>(self, values: T) -> T {
726		unsafe { deinterleave_fallback::<f32, Self::f32s, T>(values) }
727	}
728
729	#[inline(always)]
730	fn deinterleave_shfl_f64s<T: Interleave>(self, values: T) -> T {
731		unsafe { deinterleave_fallback::<f64, Self::f64s, T>(values) }
732	}
733
734	#[inline(always)]
735	fn first_true_m8s(self, mask: Self::m8s) -> usize {
736		if const { core::mem::size_of::<Self::m8s>() == core::mem::size_of::<Self::u8s>() } {
737			let mask: Self::u8s = bytemuck::cast(mask);
738			let slice = bytemuck::cast_slice::<Self::u8s, u8>(core::slice::from_ref(&mask));
739			let mut i = 0;
740			for &x in slice.iter() {
741				if x != 0 {
742					break;
743				}
744				i += 1;
745			}
746			i
747		} else if const { core::mem::size_of::<Self::m8s>() == core::mem::size_of::<u8>() } {
748			let mask: u8 = bytemuck::cast(mask);
749			mask.leading_zeros() as usize
750		} else if const { core::mem::size_of::<Self::m8s>() == core::mem::size_of::<u16>() } {
751			let mask: u16 = bytemuck::cast(mask);
752			mask.leading_zeros() as usize
753		} else {
754			panic!()
755		}
756	}
757
758	#[inline(always)]
759	fn first_true_m16s(self, mask: Self::m16s) -> usize {
760		if const { core::mem::size_of::<Self::m16s>() == core::mem::size_of::<Self::u16s>() } {
761			let mask: Self::u16s = bytemuck::cast(mask);
762			let slice = bytemuck::cast_slice::<Self::u16s, u16>(core::slice::from_ref(&mask));
763			let mut i = 0;
764			for &x in slice.iter() {
765				if x != 0 {
766					break;
767				}
768				i += 1;
769			}
770			i
771		} else if const { core::mem::size_of::<Self::m16s>() == core::mem::size_of::<u8>() } {
772			let mask: u8 = bytemuck::cast(mask);
773			mask.leading_zeros() as usize
774		} else if const { core::mem::size_of::<Self::m16s>() == core::mem::size_of::<u16>() } {
775			let mask: u16 = bytemuck::cast(mask);
776			mask.leading_zeros() as usize
777		} else {
778			panic!()
779		}
780	}
781
782	#[inline(always)]
783	fn first_true_m32s(self, mask: Self::m32s) -> usize {
784		if const { core::mem::size_of::<Self::m32s>() == core::mem::size_of::<Self::u32s>() } {
785			let mask: Self::u32s = bytemuck::cast(mask);
786			let slice = bytemuck::cast_slice::<Self::u32s, u32>(core::slice::from_ref(&mask));
787			let mut i = 0;
788			for &x in slice.iter() {
789				if x != 0 {
790					break;
791				}
792				i += 1;
793			}
794			i
795		} else if const { core::mem::size_of::<Self::m32s>() == core::mem::size_of::<u8>() } {
796			let mask: u8 = bytemuck::cast(mask);
797			mask.leading_zeros() as usize
798		} else if const { core::mem::size_of::<Self::m32s>() == core::mem::size_of::<u16>() } {
799			let mask: u16 = bytemuck::cast(mask);
800			mask.leading_zeros() as usize
801		} else {
802			panic!()
803		}
804	}
805
806	#[inline(always)]
807	fn first_true_m64s(self, mask: Self::m64s) -> usize {
808		if const { core::mem::size_of::<Self::m64s>() == core::mem::size_of::<Self::u64s>() } {
809			let mask: Self::u64s = bytemuck::cast(mask);
810			let slice = bytemuck::cast_slice::<Self::u64s, u64>(core::slice::from_ref(&mask));
811			let mut i = 0;
812			for &x in slice.iter() {
813				if x != 0 {
814					break;
815				}
816				i += 1;
817			}
818			i
819		} else if const { core::mem::size_of::<Self::m64s>() == core::mem::size_of::<u8>() } {
820			let mask: u8 = bytemuck::cast(mask);
821			mask.leading_zeros() as usize
822		} else if const { core::mem::size_of::<Self::m64s>() == core::mem::size_of::<u16>() } {
823			let mask: u16 = bytemuck::cast(mask);
824			mask.leading_zeros() as usize
825		} else {
826			panic!()
827		}
828	}
829
830	#[inline(always)]
831	fn interleave_shfl_f32s<T: Interleave>(self, values: T) -> T {
832		unsafe { interleave_fallback::<f32, Self::f32s, T>(values) }
833	}
834
835	#[inline(always)]
836	fn interleave_shfl_f64s<T: Interleave>(self, values: T) -> T {
837		unsafe { interleave_fallback::<f64, Self::f64s, T>(values) }
838	}
839
840	#[inline(always)]
841	fn mask_between_m8s(self, start: u8, end: u8) -> MemMask<Self::m8s> {
842		let iota: Self::u8s = const {
843			unsafe { core::mem::transmute_copy(&iota_8::<u8, { MAX_REGISTER_BYTES / 1 }>()) }
844		};
845		self.and_m8s(
846			self.greater_than_or_equal_u8s(iota, self.splat_u8s(start)),
847			self.less_than_u8s(iota, self.splat_u8s(end)),
848		)
849		.into()
850	}
851
852	#[inline(always)]
853	fn mask_between_m16s(self, start: u16, end: u16) -> MemMask<Self::m16s> {
854		let iota: Self::u16s = const {
855			unsafe { core::mem::transmute_copy(&iota_16::<u16, { MAX_REGISTER_BYTES / 2 }>()) }
856		};
857		self.and_m16s(
858			self.greater_than_or_equal_u16s(iota, self.splat_u16s(start)),
859			self.less_than_u16s(iota, self.splat_u16s(end)),
860		)
861		.into()
862	}
863
864	#[inline(always)]
865	fn mask_between_m32s(self, start: u32, end: u32) -> MemMask<Self::m32s> {
866		let iota: Self::u32s = const {
867			unsafe { core::mem::transmute_copy(&iota_32::<u32, { MAX_REGISTER_BYTES / 4 }>()) }
868		};
869		self.and_m32s(
870			self.greater_than_or_equal_u32s(iota, self.splat_u32s(start)),
871			self.less_than_u32s(iota, self.splat_u32s(end)),
872		)
873		.into()
874	}
875
876	#[inline(always)]
877	fn mask_between_m64s(self, start: u64, end: u64) -> MemMask<Self::m64s> {
878		let iota: Self::u64s = const {
879			unsafe { core::mem::transmute_copy(&iota_64::<u64, { MAX_REGISTER_BYTES / 8 }>()) }
880		};
881		self.and_m64s(
882			self.greater_than_or_equal_u64s(iota, self.splat_u64s(start)),
883			self.less_than_u64s(iota, self.splat_u64s(end)),
884		)
885		.into()
886	}
887	/// # Safety
888	///
889	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
890	/// [`core::ptr::read`].
891	unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s;
892	/// # Safety
893	///
894	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
895	/// [`core::ptr::read`].
896	unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s;
897	/// # Safety
898	///
899	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
900	/// [`core::ptr::read`].
901	#[inline(always)]
902	unsafe fn mask_load_ptr_f32s(self, mask: MemMask<Self::m32s>, ptr: *const f32) -> Self::f32s {
903		self.transmute_f32s_u32s(self.mask_load_ptr_u32s(mask, ptr as *const u32))
904	}
905
906	/// # Safety
907	///
908	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
909	/// [`core::ptr::read`].
910	#[inline(always)]
911	unsafe fn mask_load_ptr_f64s(self, mask: MemMask<Self::m64s>, ptr: *const f64) -> Self::f64s {
912		self.transmute_f64s_u64s(self.mask_load_ptr_u64s(mask, ptr as *const u64))
913	}
914	/// # Safety
915	///
916	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
917	/// [`core::ptr::read`].
918	#[inline(always)]
919	unsafe fn mask_load_ptr_i8s(self, mask: MemMask<Self::m8s>, ptr: *const i8) -> Self::i8s {
920		self.transmute_i8s_u8s(self.mask_load_ptr_u8s(mask, ptr as *const u8))
921	}
922	/// # Safety
923	///
924	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
925	/// [`core::ptr::read`].
926	#[inline(always)]
927	unsafe fn mask_load_ptr_i16s(self, mask: MemMask<Self::m16s>, ptr: *const i16) -> Self::i16s {
928		self.transmute_i16s_u16s(self.mask_load_ptr_u16s(mask, ptr as *const u16))
929	}
930	/// # Safety
931	///
932	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
933	/// [`core::ptr::read`].
934	#[inline(always)]
935	unsafe fn mask_load_ptr_i32s(self, mask: MemMask<Self::m32s>, ptr: *const i32) -> Self::i32s {
936		self.transmute_i32s_u32s(self.mask_load_ptr_u32s(mask, ptr as *const u32))
937	}
938	/// # Safety
939	///
940	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
941	/// [`core::ptr::read`].
942	#[inline(always)]
943	unsafe fn mask_load_ptr_i64s(self, mask: MemMask<Self::m64s>, ptr: *const i64) -> Self::i64s {
944		self.transmute_i64s_u64s(self.mask_load_ptr_u64s(mask, ptr as *const u64))
945	}
946
947	/// # Safety
948	///
949	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
950	/// [`core::ptr::read`].
951	unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s;
952
953	/// # Safety
954	///
955	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
956	/// [`core::ptr::read`].
957	unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s;
958
959	/// # Safety
960	///
961	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
962	/// [`core::ptr::read`].
963	unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s;
964
965	/// # Safety
966	///
967	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
968	/// [`core::ptr::read`].
969	unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s;
970	/// # Safety
971	///
972	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
973	/// [`core::ptr::write`].
974	unsafe fn mask_store_ptr_c32s(
975		self,
976		mask: MemMask<Self::m32s>,
977		ptr: *mut c32,
978		values: Self::c32s,
979	);
980	/// # Safety
981	///
982	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
983	/// [`core::ptr::write`].
984	unsafe fn mask_store_ptr_c64s(
985		self,
986		mask: MemMask<Self::m64s>,
987		ptr: *mut c64,
988		values: Self::c64s,
989	);
990	/// # Safety
991	///
992	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
993	/// [`core::ptr::write`].
994	#[inline(always)]
995	unsafe fn mask_store_ptr_f32s(
996		self,
997		mask: MemMask<Self::m32s>,
998		ptr: *mut f32,
999		values: Self::f32s,
1000	) {
1001		self.mask_store_ptr_u32s(mask, ptr as *mut u32, self.transmute_u32s_f32s(values));
1002	}
1003
1004	/// # Safety
1005	///
1006	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1007	/// [`core::ptr::write`].
1008	#[inline(always)]
1009	unsafe fn mask_store_ptr_f64s(
1010		self,
1011		mask: MemMask<Self::m64s>,
1012		ptr: *mut f64,
1013		values: Self::f64s,
1014	) {
1015		self.mask_store_ptr_u64s(mask, ptr as *mut u64, self.transmute_u64s_f64s(values));
1016	}
1017	/// # Safety
1018	///
1019	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1020	/// [`core::ptr::write`].
1021	#[inline(always)]
1022	unsafe fn mask_store_ptr_i8s(self, mask: MemMask<Self::m8s>, ptr: *mut i8, values: Self::i8s) {
1023		self.mask_store_ptr_u8s(mask, ptr as *mut u8, self.transmute_u8s_i8s(values));
1024	}
1025	/// # Safety
1026	///
1027	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1028	/// [`core::ptr::write`].
1029	#[inline(always)]
1030	unsafe fn mask_store_ptr_i16s(
1031		self,
1032		mask: MemMask<Self::m16s>,
1033		ptr: *mut i16,
1034		values: Self::i16s,
1035	) {
1036		self.mask_store_ptr_u16s(mask, ptr as *mut u16, self.transmute_u16s_i16s(values));
1037	}
1038	/// # Safety
1039	///
1040	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1041	/// [`core::ptr::write`].
1042	#[inline(always)]
1043	unsafe fn mask_store_ptr_i32s(
1044		self,
1045		mask: MemMask<Self::m32s>,
1046		ptr: *mut i32,
1047		values: Self::i32s,
1048	) {
1049		self.mask_store_ptr_u32s(mask, ptr as *mut u32, self.transmute_u32s_i32s(values));
1050	}
1051	/// # Safety
1052	///
1053	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1054	/// [`core::ptr::write`].
1055	#[inline(always)]
1056	unsafe fn mask_store_ptr_i64s(
1057		self,
1058		mask: MemMask<Self::m64s>,
1059		ptr: *mut i64,
1060		values: Self::i64s,
1061	) {
1062		self.mask_store_ptr_u64s(mask, ptr as *mut u64, self.transmute_u64s_i64s(values));
1063	}
1064
1065	/// # Safety
1066	///
1067	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1068	/// [`core::ptr::write`].
1069	unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s);
1070
1071	/// # Safety
1072	///
1073	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1074	/// [`core::ptr::write`].
1075	unsafe fn mask_store_ptr_u16s(
1076		self,
1077		mask: MemMask<Self::m16s>,
1078		ptr: *mut u16,
1079		values: Self::u16s,
1080	);
1081
1082	/// # Safety
1083	///
1084	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1085	/// [`core::ptr::write`].
1086	unsafe fn mask_store_ptr_u32s(
1087		self,
1088		mask: MemMask<Self::m32s>,
1089		ptr: *mut u32,
1090		values: Self::u32s,
1091	);
1092
1093	/// # Safety
1094	///
1095	/// Addresses corresponding to enabled lanes in the mask have the same restrictions as
1096	/// [`core::ptr::write`].
1097	unsafe fn mask_store_ptr_u64s(
1098		self,
1099		mask: MemMask<Self::m64s>,
1100		ptr: *mut u64,
1101		values: Self::u64s,
1102	);
1103
1104	fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s;
1105	fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s;
1106	/// Computes `a * b + c`
1107	#[inline]
1108	fn mul_add_e_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
1109		self.mul_add_c32s(a, b, c)
1110	}
1111	/// Computes `a * b + c`
1112	#[inline]
1113	fn mul_add_e_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
1114		self.mul_add_c64s(a, b, c)
1115	}
1116	fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
1117	fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
1118	fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s;
1119	fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s;
1120
1121	/// Computes `-a * b + c`
1122	#[inline(always)]
1123	fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1124		self.mul_add_e_f32s(self.neg_f32s(a), b, c)
1125	}
1126	#[inline(always)]
1127	fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1128		self.mul_add_e_f64s(self.neg_f64s(a), b, c)
1129	}
1130	#[inline(always)]
1131	fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1132		self.mul_add_f32s(self.neg_f32s(a), b, c)
1133	}
1134	#[inline(always)]
1135	fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
1136		self.mul_add_f64s(self.neg_f64s(a), b, c)
1137	}
1138
1139	/// Computes `a * b`
1140	#[inline]
1141	fn mul_e_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
1142		self.mul_c32s(a, b)
1143	}
1144	/// Computes `a * b`
1145	fn mul_e_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
1146		self.mul_c64s(a, b)
1147	}
1148
1149	#[inline]
1150	fn neg_f32s(self, a: Self::f32s) -> Self::f32s {
1151		self.xor_f32s(self.splat_f32s(-0.0), a)
1152	}
1153	#[inline]
1154	fn neg_f64s(self, a: Self::f64s) -> Self::f64s {
1155		self.xor_f64s(a, self.splat_f64s(-0.0))
1156	}
1157
1158	#[inline(always)]
1159	fn partial_load_c32s(self, slice: &[c32]) -> Self::c32s {
1160		cast(self.partial_load_f64s(bytemuck::cast_slice(slice)))
1161	}
1162	#[inline(always)]
1163	fn partial_load_c64s(self, slice: &[c64]) -> Self::c64s {
1164		cast(self.partial_load_f64s(bytemuck::cast_slice(slice)))
1165	}
1166	#[inline(always)]
1167	fn partial_load_f32s(self, slice: &[f32]) -> Self::f32s {
1168		cast(self.partial_load_u32s(bytemuck::cast_slice(slice)))
1169	}
1170	#[inline(always)]
1171	fn partial_load_f64s(self, slice: &[f64]) -> Self::f64s {
1172		cast(self.partial_load_u64s(bytemuck::cast_slice(slice)))
1173	}
1174	#[inline(always)]
1175	fn partial_load_i8s(self, slice: &[i8]) -> Self::i8s {
1176		cast(self.partial_load_u8s(bytemuck::cast_slice(slice)))
1177	}
1178	#[inline(always)]
1179	fn partial_load_i16s(self, slice: &[i16]) -> Self::i16s {
1180		cast(self.partial_load_u16s(bytemuck::cast_slice(slice)))
1181	}
1182	#[inline(always)]
1183	fn partial_load_i32s(self, slice: &[i32]) -> Self::i32s {
1184		cast(self.partial_load_u32s(bytemuck::cast_slice(slice)))
1185	}
1186	#[inline(always)]
1187	fn partial_load_i64s(self, slice: &[i64]) -> Self::i64s {
1188		cast(self.partial_load_u64s(bytemuck::cast_slice(slice)))
1189	}
1190	#[inline(always)]
1191	fn partial_load_u8s(self, slice: &[u8]) -> Self::u8s {
1192		unsafe {
1193			self.mask_load_ptr_u8s(self.mask_between_m8s(0, slice.len() as u8), slice.as_ptr())
1194		}
1195	}
1196	#[inline(always)]
1197	fn partial_load_u16s(self, slice: &[u16]) -> Self::u16s {
1198		unsafe {
1199			self.mask_load_ptr_u16s(
1200				self.mask_between_m16s(0, slice.len() as u16),
1201				slice.as_ptr(),
1202			)
1203		}
1204	}
1205	#[inline(always)]
1206	fn partial_load_u32s(self, slice: &[u32]) -> Self::u32s {
1207		unsafe {
1208			self.mask_load_ptr_u32s(
1209				self.mask_between_m32s(0, slice.len() as u32),
1210				slice.as_ptr(),
1211			)
1212		}
1213	}
1214	#[inline(always)]
1215	fn partial_load_u64s(self, slice: &[u64]) -> Self::u64s {
1216		unsafe {
1217			self.mask_load_ptr_u64s(
1218				self.mask_between_m64s(0, slice.len() as u64),
1219				slice.as_ptr(),
1220			)
1221		}
1222	}
1223
1224	#[inline(always)]
1225	fn partial_store_c32s(self, slice: &mut [c32], values: Self::c32s) {
1226		self.partial_store_f64s(bytemuck::cast_slice_mut(slice), cast(values))
1227	}
1228	#[inline(always)]
1229	fn partial_store_c64s(self, slice: &mut [c64], values: Self::c64s) {
1230		self.partial_store_f64s(bytemuck::cast_slice_mut(slice), cast(values))
1231	}
1232
1233	#[inline(always)]
1234	fn partial_store_f32s(self, slice: &mut [f32], values: Self::f32s) {
1235		self.partial_store_u32s(bytemuck::cast_slice_mut(slice), cast(values))
1236	}
1237	#[inline(always)]
1238	fn partial_store_f64s(self, slice: &mut [f64], values: Self::f64s) {
1239		self.partial_store_u64s(bytemuck::cast_slice_mut(slice), cast(values))
1240	}
1241	#[inline(always)]
1242	fn partial_store_i8s(self, slice: &mut [i8], values: Self::i8s) {
1243		self.partial_store_u16s(bytemuck::cast_slice_mut(slice), cast(values))
1244	}
1245	#[inline(always)]
1246	fn partial_store_i16s(self, slice: &mut [i16], values: Self::i16s) {
1247		self.partial_store_u16s(bytemuck::cast_slice_mut(slice), cast(values))
1248	}
1249	#[inline(always)]
1250	fn partial_store_i32s(self, slice: &mut [i32], values: Self::i32s) {
1251		self.partial_store_u32s(bytemuck::cast_slice_mut(slice), cast(values))
1252	}
1253	#[inline(always)]
1254	fn partial_store_i64s(self, slice: &mut [i64], values: Self::i64s) {
1255		self.partial_store_u64s(bytemuck::cast_slice_mut(slice), cast(values))
1256	}
1257	#[inline(always)]
1258	fn partial_store_u8s(self, slice: &mut [u8], values: Self::u8s) {
1259		unsafe {
1260			self.mask_store_ptr_u8s(
1261				self.mask_between_m8s(0, slice.len() as u8),
1262				slice.as_mut_ptr(),
1263				values,
1264			)
1265		}
1266	}
1267	#[inline(always)]
1268	fn partial_store_u16s(self, slice: &mut [u16], values: Self::u16s) {
1269		unsafe {
1270			self.mask_store_ptr_u16s(
1271				self.mask_between_m16s(0, slice.len() as u16),
1272				slice.as_mut_ptr(),
1273				values,
1274			)
1275		}
1276	}
1277	#[inline(always)]
1278	fn partial_store_u32s(self, slice: &mut [u32], values: Self::u32s) {
1279		unsafe {
1280			self.mask_store_ptr_u32s(
1281				self.mask_between_m32s(0, slice.len() as u32),
1282				slice.as_mut_ptr(),
1283				values,
1284			)
1285		}
1286	}
1287	#[inline(always)]
1288	fn partial_store_u64s(self, slice: &mut [u64], values: Self::u64s) {
1289		unsafe {
1290			self.mask_store_ptr_u64s(
1291				self.mask_between_m64s(0, slice.len() as u64),
1292				slice.as_mut_ptr(),
1293				values,
1294			)
1295		}
1296	}
1297	fn reduce_max_c32s(self, a: Self::c32s) -> c32;
1298	fn reduce_max_c64s(self, a: Self::c64s) -> c64;
1299	fn reduce_max_f32s(self, a: Self::f32s) -> f32;
1300	fn reduce_max_f64s(self, a: Self::f64s) -> f64;
1301	fn reduce_min_c32s(self, a: Self::c32s) -> c32;
1302	fn reduce_min_c64s(self, a: Self::c64s) -> c64;
1303	fn reduce_min_f32s(self, a: Self::f32s) -> f32;
1304	fn reduce_min_f64s(self, a: Self::f64s) -> f64;
1305
1306	fn reduce_product_f32s(self, a: Self::f32s) -> f32;
1307	fn reduce_product_f64s(self, a: Self::f64s) -> f64;
1308	fn reduce_sum_c32s(self, a: Self::c32s) -> c32;
1309	fn reduce_sum_c64s(self, a: Self::c64s) -> c64;
1310
1311	fn reduce_sum_f32s(self, a: Self::f32s) -> f32;
1312	fn reduce_sum_f64s(self, a: Self::f64s) -> f64;
1313	#[inline(always)]
1314	fn rotate_left_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
1315		self.rotate_right_c32s(a, amount.wrapping_neg())
1316	}
1317	#[inline(always)]
1318	fn rotate_left_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
1319		self.rotate_right_c64s(a, amount.wrapping_neg())
1320	}
1321
1322	#[inline(always)]
1323	fn rotate_left_f32s(self, a: Self::f32s, amount: usize) -> Self::f32s {
1324		cast(self.rotate_left_u32s(cast(a), amount))
1325	}
1326	#[inline(always)]
1327	fn rotate_left_f64s(self, a: Self::f64s, amount: usize) -> Self::f64s {
1328		cast(self.rotate_left_u64s(cast(a), amount))
1329	}
1330	#[inline(always)]
1331	fn rotate_left_i32s(self, a: Self::i32s, amount: usize) -> Self::i32s {
1332		cast(self.rotate_left_u32s(cast(a), amount))
1333	}
1334
1335	#[inline(always)]
1336	fn rotate_left_i64s(self, a: Self::i64s, amount: usize) -> Self::i64s {
1337		cast(self.rotate_left_u64s(cast(a), amount))
1338	}
1339
1340	#[inline(always)]
1341	fn rotate_left_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
1342		self.rotate_right_u32s(a, amount.wrapping_neg())
1343	}
1344	#[inline(always)]
1345	fn rotate_left_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
1346		self.rotate_right_u64s(a, amount.wrapping_neg())
1347	}
1348	fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s;
1349	fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s;
1350	#[inline(always)]
1351	fn rotate_right_f32s(self, a: Self::f32s, amount: usize) -> Self::f32s {
1352		cast(self.rotate_right_u32s(cast(a), amount))
1353	}
1354	#[inline(always)]
1355	fn rotate_right_f64s(self, a: Self::f64s, amount: usize) -> Self::f64s {
1356		cast(self.rotate_right_u64s(cast(a), amount))
1357	}
1358	#[inline(always)]
1359	fn rotate_right_i32s(self, a: Self::i32s, amount: usize) -> Self::i32s {
1360		cast(self.rotate_right_u32s(cast(a), amount))
1361	}
1362	#[inline(always)]
1363	fn rotate_right_i64s(self, a: Self::i64s, amount: usize) -> Self::i64s {
1364		cast(self.rotate_right_u64s(cast(a), amount))
1365	}
1366	fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s;
1367	fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s;
1368
1369	#[inline]
1370	fn select_f32s(
1371		self,
1372		mask: Self::m32s,
1373		if_true: Self::f32s,
1374		if_false: Self::f32s,
1375	) -> Self::f32s {
1376		self.transmute_f32s_u32s(self.select_u32s(
1377			mask,
1378			self.transmute_u32s_f32s(if_true),
1379			self.transmute_u32s_f32s(if_false),
1380		))
1381	}
1382	#[inline]
1383	fn select_f64s(
1384		self,
1385		mask: Self::m64s,
1386		if_true: Self::f64s,
1387		if_false: Self::f64s,
1388	) -> Self::f64s {
1389		self.transmute_f64s_u64s(self.select_u64s(
1390			mask,
1391			self.transmute_u64s_f64s(if_true),
1392			self.transmute_u64s_f64s(if_false),
1393		))
1394	}
1395	#[inline]
1396	fn select_i32s(
1397		self,
1398		mask: Self::m32s,
1399		if_true: Self::i32s,
1400		if_false: Self::i32s,
1401	) -> Self::i32s {
1402		self.transmute_i32s_u32s(self.select_u32s(
1403			mask,
1404			self.transmute_u32s_i32s(if_true),
1405			self.transmute_u32s_i32s(if_false),
1406		))
1407	}
1408	#[inline]
1409	fn select_i64s(
1410		self,
1411		mask: Self::m64s,
1412		if_true: Self::i64s,
1413		if_false: Self::i64s,
1414	) -> Self::i64s {
1415		self.transmute_i64s_u64s(self.select_u64s(
1416			mask,
1417			self.transmute_u64s_i64s(if_true),
1418			self.transmute_u64s_i64s(if_false),
1419		))
1420	}
1421	fn select_u32s(self, mask: Self::m32s, if_true: Self::u32s, if_false: Self::u32s)
1422	-> Self::u32s;
1423	fn select_u64s(self, mask: Self::m64s, if_true: Self::u64s, if_false: Self::u64s)
1424	-> Self::u64s;
1425
1426	fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s;
1427	fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s;
1428
1429	#[inline]
1430	fn transmute_f32s_i32s(self, a: Self::i32s) -> Self::f32s {
1431		cast(a)
1432	}
1433	#[inline]
1434	fn transmute_f32s_u32s(self, a: Self::u32s) -> Self::f32s {
1435		cast(a)
1436	}
1437
1438	#[inline]
1439	fn transmute_f64s_i64s(self, a: Self::i64s) -> Self::f64s {
1440		cast(a)
1441	}
1442	#[inline]
1443	fn transmute_f64s_u64s(self, a: Self::u64s) -> Self::f64s {
1444		cast(a)
1445	}
1446	#[inline]
1447	fn transmute_i32s_f32s(self, a: Self::f32s) -> Self::i32s {
1448		cast(a)
1449	}
1450	#[inline]
1451	fn transmute_m8s_u8s(self, a: Self::u8s) -> Self::m8s {
1452		checked::cast(a)
1453	}
1454	#[inline]
1455	fn transmute_u8s_m8s(self, a: Self::m8s) -> Self::u8s {
1456		cast(a)
1457	}
1458	#[inline]
1459	fn transmute_m16s_u16s(self, a: Self::u16s) -> Self::m16s {
1460		checked::cast(a)
1461	}
1462	#[inline]
1463	fn transmute_u16s_m16s(self, a: Self::m16s) -> Self::u16s {
1464		cast(a)
1465	}
1466	#[inline]
1467	fn transmute_m32s_u32s(self, a: Self::u32s) -> Self::m32s {
1468		checked::cast(a)
1469	}
1470	#[inline]
1471	fn transmute_u32s_m32s(self, a: Self::m32s) -> Self::u32s {
1472		cast(a)
1473	}
1474	#[inline]
1475	fn transmute_m64s_u64s(self, a: Self::u64s) -> Self::m64s {
1476		checked::cast(a)
1477	}
1478	#[inline]
1479	fn transmute_u64s_m64s(self, a: Self::m64s) -> Self::u64s {
1480		cast(a)
1481	}
1482	#[inline]
1483	fn transmute_i8s_u8s(self, a: Self::u8s) -> Self::i8s {
1484		cast(a)
1485	}
1486	#[inline]
1487	fn transmute_u8s_i8s(self, a: Self::i8s) -> Self::u8s {
1488		cast(a)
1489	}
1490	#[inline]
1491	fn transmute_u16s_i16s(self, a: Self::i16s) -> Self::u16s {
1492		cast(a)
1493	}
1494	#[inline]
1495	fn transmute_i16s_u16s(self, a: Self::u16s) -> Self::i16s {
1496		cast(a)
1497	}
1498	#[inline]
1499	fn transmute_i32s_u32s(self, a: Self::u32s) -> Self::i32s {
1500		cast(a)
1501	}
1502	#[inline]
1503	fn transmute_i64s_f64s(self, a: Self::f64s) -> Self::i64s {
1504		cast(a)
1505	}
1506	#[inline]
1507	fn transmute_i64s_u64s(self, a: Self::u64s) -> Self::i64s {
1508		cast(a)
1509	}
1510
1511	#[inline]
1512	fn transmute_u32s_f32s(self, a: Self::f32s) -> Self::u32s {
1513		cast(a)
1514	}
1515	#[inline]
1516	fn transmute_u32s_i32s(self, a: Self::i32s) -> Self::u32s {
1517		cast(a)
1518	}
1519	#[inline]
1520	fn transmute_u64s_f64s(self, a: Self::f64s) -> Self::u64s {
1521		cast(a)
1522	}
1523	#[inline]
1524	fn transmute_u64s_i64s(self, a: Self::i64s) -> Self::u64s {
1525		cast(a)
1526	}
1527
1528	fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output;
1529	fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s);
1530	fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
1531	fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s;
1532}
1533
1534pub trait PortableSimd: Simd {}
1535
1536impl PortableSimd for Scalar {}
1537impl PortableSimd for Scalar128b {}
1538impl PortableSimd for Scalar256b {}
1539impl PortableSimd for Scalar512b {}
1540
1541#[derive(Debug, Copy, Clone)]
1542pub struct Scalar;
1543
1544#[derive(Debug, Copy, Clone)]
1545pub struct Scalar128b;
1546#[derive(Debug, Copy, Clone)]
1547pub struct Scalar256b;
1548#[derive(Debug, Copy, Clone)]
1549pub struct Scalar512b;
1550
1551macro_rules! scalar_simd_binop_impl {
1552	($func: ident, $op: ident, $ty: ty) => {
1553		paste! {
1554			#[inline]
1555			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>],) -> Self::[<$ty s>] {
1556				let mut out = [<$ty as Default>::default(); Self::[<$ty:upper _LANES>]];
1557				let a: [$ty; Self::[<$ty:upper _LANES>]] = cast(a);
1558				let b: [$ty; Self::[<$ty:upper _LANES>]] = cast(b);
1559
1560				for i in 0..Self::[<$ty:upper _LANES>] {
1561					out[i] = a[i].$op(b[i]);
1562				}
1563
1564				cast(out)
1565			}
1566		}
1567	};
1568}
1569
1570macro_rules! scalar_simd_binop {
1571	($func: ident, op $op: ident, $($ty: ty),*) => {
1572		$(scalar_simd_binop_impl!($func, $op, $ty);)*
1573	};
1574	($func: ident, $($ty: ty),*) => {
1575		$(scalar_simd_binop_impl!($func, $func, $ty);)*
1576	};
1577}
1578
1579macro_rules! scalar_simd_unop_impl {
1580	($func: ident, $op: ident, $ty: ty) => {
1581		paste! {
1582			#[inline]
1583			fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$ty s>] {
1584				let mut out = [<$ty as Default>::default(); Self::[<$ty:upper _LANES>]];
1585				let a: [$ty; Self::[<$ty:upper _LANES>]] = cast(a);
1586
1587				for i in 0..Self::[<$ty:upper _LANES>] {
1588					out[i] = a[i].$op();
1589				}
1590
1591				cast(out)
1592			}
1593		}
1594	};
1595}
1596
1597macro_rules! scalar_simd_unop {
1598	($func: ident, $($ty: ty),*) => {
1599		$(scalar_simd_unop_impl!($func, $func, $ty);)*
1600	};
1601}
1602
1603macro_rules! scalar_simd_cmp {
1604	($func: ident, $op: ident, $ty: ty, $mask: ty) => {
1605		paste! {
1606			#[inline]
1607			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$mask s>] {
1608				let mut out = [$mask::new(false); Self::[<$ty:upper _LANES>]];
1609				let a: [$ty; Self::[<$ty:upper _LANES>]] = cast(a);
1610				let b: [$ty; Self::[<$ty:upper _LANES>]] = cast(b);
1611				for i in 0..Self::[<$ty:upper _LANES>] {
1612					out[i] = $mask::new(a[i].$op(&b[i]));
1613				}
1614				cast(out)
1615			}
1616		}
1617	};
1618	($func: ident, op $op: ident, $($ty: ty => $mask: ty),*) => {
1619		$(scalar_simd_cmp!($func, $op, $ty, $mask);)*
1620	};
1621	($func: ident, $($ty: ty => $mask: ty),*) => {
1622		$(scalar_simd_cmp!($func, $func, $ty, $mask);)*
1623	};
1624}
1625
1626macro_rules! scalar_splat {
1627	($ty: ident) => {
1628		paste! {
1629			#[inline]
1630			fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>] {
1631				cast([value; Self::[<$ty:upper _LANES>]])
1632			}
1633		}
1634	};
1635	($($ty: ident),*) => {
1636		$(scalar_splat!($ty);)*
1637	};
1638}
1639
1640macro_rules! scalar_partial_load {
1641	($ty: ident) => {
1642		paste! {
1643			#[inline]
1644			fn [<partial_load_ $ty s>](self, slice: &[$ty]) -> Self::[<$ty s>] {
1645				let mut values = [<$ty as Default>::default(); Self::[<$ty:upper _LANES>]];
1646				for i in 0..Ord::min(values.len(), slice.len()) {
1647					values[i] = slice[i];
1648				}
1649				cast(values)
1650			}
1651		}
1652	};
1653	($($ty: ident),*) => {
1654		$(scalar_partial_load!($ty);)*
1655	};
1656}
1657
1658macro_rules! scalar_partial_store {
1659	($ty: ident) => {
1660		paste! {
1661			#[inline]
1662			fn [<partial_store_ $ty s>](self, slice: &mut [$ty], values: Self::[<$ty s>]) {
1663				let values: [$ty; Self::[<$ty:upper _LANES>]] = cast(values);
1664				for i in 0..Ord::min(values.len(), slice.len()) {
1665					slice[i] = values[i];
1666				}
1667			}
1668		}
1669	};
1670	($($ty: ident),*) => {
1671		$(scalar_partial_store!($ty);)*
1672	};
1673}
1674
1675macro_rules! mask_load_ptr {
1676	($ty: ident, $mask: ident) => {
1677		paste! {
1678			#[inline]
1679			unsafe fn [<mask_load_ptr_ $ty s>](
1680				self,
1681				mask: MemMask<Self::[<$mask s>]>,
1682				ptr: *const $ty,
1683			) -> Self::[<$ty s>] {
1684				let mut values = [<$ty as Default>::default(); Self::[<$ty:upper _LANES>]];
1685				let mask: [$mask; Self::[<$ty:upper _LANES>]] = cast(mask.mask());
1686				for i in 0..Self::[<$ty:upper _LANES>] {
1687					if mask[i].is_set() {
1688						values[i] = *ptr.add(i);
1689					}
1690				}
1691				cast(values)
1692			}
1693		}
1694	};
1695	(cast $ty: ident, $to: ident, $mask: ident) => {
1696		paste! {
1697			#[inline]
1698			unsafe fn [<mask_load_ptr_ $ty s>](
1699				self,
1700				mask: MemMask<Self::[<$mask s>]>,
1701				ptr: *const $ty,
1702			) -> Self::[<$ty s>] {
1703				cast(self.[<mask_load_ptr_ $to s>](mask, ptr as *const $to))
1704			}
1705		}
1706	};
1707	($($ty: ident: $mask: ident),*) => {
1708		$(mask_load_ptr!($ty, $mask);)*
1709	};
1710	(cast $($ty: ident: $mask: ident => $to: ident),*) => {
1711		$(mask_load_ptr!(cast $ty, $to, $mask);)*
1712	};
1713}
1714
1715macro_rules! mask_store_ptr {
1716	($ty: ident, $mask: ident) => {
1717		paste! {
1718			#[inline]
1719			unsafe fn [<mask_store_ptr_ $ty s>](
1720				self,
1721				mask: MemMask<Self::[<$mask s>]>,
1722				ptr: *mut $ty,
1723				values: Self::[<$ty s>],
1724			) {
1725				let mask: [$mask; Self::[<$ty:upper _LANES>]] = cast(mask.mask());
1726				let values: [$ty; Self::[<$ty:upper _LANES>]] = cast(values);
1727				for i in 0..Self::[<$ty:upper _LANES>] {
1728					if mask[i].is_set() {
1729						*ptr.add(i) = values[i];
1730					}
1731				}
1732			}
1733		}
1734	};
1735	(cast $ty: ident, $to: ident, $mask: ident) => {
1736		paste! {
1737			#[inline]
1738			unsafe fn [<mask_store_ptr_ $ty s>](
1739				self,
1740				mask: MemMask<Self::[<$mask s>]>,
1741				ptr: *mut $ty,
1742				values: Self::[<$ty s>],
1743			) {
1744				self.[<mask_store_ptr_ $to s>](mask, ptr as *mut $to, cast(values));
1745			}
1746		}
1747	};
1748	($($ty: ident: $mask: ident),*) => {
1749		$(mask_store_ptr!($ty, $mask);)*
1750	};
1751	(cast $($ty: ident: $mask: ident => $to: ident),*) => {
1752		$(mask_store_ptr!(cast $ty, $to, $mask);)*
1753	};
1754}
1755
1756macro_rules! scalar_simd {
1757	($ty: ty, $register_count: expr, $m8s: ty, $i8s: ty, $u8s: ty, $m16s: ty, $i16s: ty, $u16s: ty, $m32s: ty, $f32s: ty, $i32s: ty, $u32s: ty, $m64s: ty, $f64s: ty, $i64s: ty, $u64s: ty $(,)?) => {
1758		impl Seal for $ty {}
1759		impl Simd for $ty {
1760			type m8s = $m8s;
1761			type m16s = $m16s;
1762			type c32s = $f32s;
1763			type c64s = $f64s;
1764			type f32s = $f32s;
1765			type f64s = $f64s;
1766			type i16s = $i16s;
1767			type i32s = $i32s;
1768			type i64s = $i64s;
1769			type i8s = $i8s;
1770			type m32s = $m32s;
1771			type m64s = $m64s;
1772			type u16s = $u16s;
1773			type u32s = $u32s;
1774			type u64s = $u64s;
1775			type u8s = $u8s;
1776
1777			const REGISTER_COUNT: usize = $register_count;
1778
1779			scalar_simd_binop!(min, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
1780
1781			scalar_simd_binop!(max, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
1782
1783			scalar_simd_binop!(add, c32, f32, c64, f64);
1784			scalar_simd_binop!(add, op wrapping_add, u8, i8, u16, i16, u32, i32, u64, i64);
1785			scalar_simd_binop!(sub, c32, f32, c64, f64);
1786			scalar_simd_binop!(sub, op wrapping_sub, u8, i8, u16, i16, u32, i32, u64, i64);
1787			scalar_simd_binop!(mul, c32, f32, c64, f64);
1788			scalar_simd_binop!(mul, op wrapping_mul, u16, i16, u32, i32, u64, i64);
1789			scalar_simd_binop!(div, f32, f64);
1790
1791			scalar_simd_binop!(and, op bitand, u8, u16, u32, u64);
1792			scalar_simd_binop!(or,  op bitor, u8, u16, u32, u64);
1793			scalar_simd_binop!(xor, op bitxor, u8, u16, u32, u64);
1794
1795			scalar_simd_cmp!(equal, op eq, u8 => m8, u16 => m16, u32 => m32, u64 => m64, c32 => m32, f32 => m32, c64 => m64, f64 => m64);
1796			scalar_simd_cmp!(greater_than, op gt, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
1797			scalar_simd_cmp!(greater_than_or_equal, op ge, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
1798			scalar_simd_cmp!(less_than_or_equal, op le, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
1799			scalar_simd_cmp!(less_than, op lt, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
1800
1801			scalar_simd_unop!(not, m8, u8, m16, u16, m32, u32, m64, u64);
1802
1803			scalar_splat!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
1804
1805			scalar_partial_load!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
1806			scalar_partial_store!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
1807
1808			mask_load_ptr!(u8: m8, u16: m16, u32: m32, u64: m64);
1809			mask_load_ptr!(cast i8: m8 => u8, i16: m16 => u16, i32: m32 => u32, i64: m64 => u64, c32: m32 => u32, f32: m32 => u32, c64: m64 => u64, f64: m64 => u64);
1810			mask_store_ptr!(u8: m8, u16: m16, u32: m32, u64: m64);
1811			mask_store_ptr!(cast i8: m8 => u8, i16: m16 => u16, i32: m32 => u32, i64: m64 => u64, c32: m32 => u32, f32: m32 => u32, c64: m64 => u64, f64: m64 => u64);
1812
1813			#[inline]
1814			fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
1815				op.with_simd(self)
1816			}
1817
1818			#[inline]
1819			fn and_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s {
1820				let mut out = [m32::new(false); Self::F32_LANES];
1821				let a: [m32; Self::F32_LANES] = cast(a);
1822				let b: [m32; Self::F32_LANES] = cast(b);
1823				for i in 0..Self::F32_LANES {
1824					out[i] = a[i] & b[i];
1825				}
1826				cast(out)
1827			}
1828
1829			#[inline]
1830			fn or_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s {
1831				let mut out = [m32::new(false); Self::F32_LANES];
1832				let a: [m32; Self::F32_LANES] = cast(a);
1833				let b: [m32; Self::F32_LANES] = cast(b);
1834				for i in 0..Self::F32_LANES {
1835					out[i] = a[i] | b[i];
1836				}
1837				cast(out)
1838			}
1839
1840			#[inline]
1841			fn xor_m32s(self, a: Self::m32s, b: Self::m32s) -> Self::m32s {
1842				let mut out = [m32::new(false); Self::F32_LANES];
1843				let a: [m32; Self::F32_LANES] = cast(a);
1844				let b: [m32; Self::F32_LANES] = cast(b);
1845				for i in 0..Self::F32_LANES {
1846					out[i] = a[i] ^ b[i];
1847				}
1848				cast(out)
1849			}
1850
1851			#[inline]
1852			fn and_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s {
1853				let mut out = [m64::new(false); Self::F64_LANES];
1854				let a: [m64; Self::F64_LANES] = cast(a);
1855				let b: [m64; Self::F64_LANES] = cast(b);
1856				for i in 0..Self::F64_LANES {
1857					out[i] = a[i] & b[i];
1858				}
1859				cast(out)
1860			}
1861
1862			#[inline]
1863			fn or_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s {
1864				let mut out = [m64::new(false); Self::F64_LANES];
1865				let a: [m64; Self::F64_LANES] = cast(a);
1866				let b: [m64; Self::F64_LANES] = cast(b);
1867				for i in 0..Self::F64_LANES {
1868					out[i] = a[i] | b[i];
1869				}
1870				cast(out)
1871			}
1872
1873			#[inline]
1874			fn xor_m64s(self, a: Self::m64s, b: Self::m64s) -> Self::m64s {
1875				let mut out = [m64::new(false); Self::F64_LANES];
1876				let a: [m64; Self::F64_LANES] = cast(a);
1877				let b: [m64; Self::F64_LANES] = cast(b);
1878				for i in 0..Self::F64_LANES {
1879					out[i] = a[i] ^ b[i];
1880				}
1881				cast(out)
1882			}
1883
1884			#[inline]
1885			fn select_u32s(
1886				self,
1887				mask: Self::m32s,
1888				if_true: Self::u32s,
1889				if_false: Self::u32s,
1890			) -> Self::u32s {
1891				let mut out = [0u32; Self::F32_LANES];
1892				let mask: [m32; Self::F32_LANES] = cast(mask);
1893				let if_true: [u32; Self::F32_LANES] = cast(if_true);
1894				let if_false: [u32; Self::F32_LANES] = cast(if_false);
1895
1896				for i in 0..Self::F32_LANES {
1897					out[i] = if mask[i].is_set() {
1898						if_true[i]
1899					} else {
1900						if_false[i]
1901					};
1902				}
1903
1904				cast(out)
1905			}
1906
1907			#[inline]
1908			fn select_u64s(
1909				self,
1910				mask: Self::m64s,
1911				if_true: Self::u64s,
1912				if_false: Self::u64s,
1913			) -> Self::u64s {
1914				let mut out = [0u64; Self::F64_LANES];
1915				let mask: [m64; Self::F64_LANES] = cast(mask);
1916				let if_true: [u64; Self::F64_LANES] = cast(if_true);
1917				let if_false: [u64; Self::F64_LANES] = cast(if_false);
1918
1919				for i in 0..Self::F64_LANES {
1920					out[i] = if mask[i].is_set() {
1921						if_true[i]
1922					} else {
1923						if_false[i]
1924					};
1925				}
1926
1927				cast(out)
1928			}
1929
1930			#[inline]
1931			fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1932				let mut out = [0u32; Self::F32_LANES];
1933				let a: [u32; Self::F32_LANES] = cast(a);
1934				let b: [u32; Self::F32_LANES] = cast(amount);
1935				for i in 0..Self::F32_LANES {
1936					out[i] = a[i].wrapping_shl(b[i]);
1937				}
1938				cast(out)
1939			}
1940
1941			#[inline]
1942			fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
1943				let mut out = [0u32; Self::F32_LANES];
1944				let a: [u32; Self::F32_LANES] = cast(a);
1945				let b: [u32; Self::F32_LANES] = cast(amount);
1946				for i in 0..Self::F32_LANES {
1947					out[i] = a[i].wrapping_shr(b[i]);
1948				}
1949				cast(out)
1950			}
1951
1952			#[inline]
1953			fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
1954				let mut lo = [0u32; Self::F32_LANES];
1955				let mut hi = [0u32; Self::F32_LANES];
1956				let a: [u32; Self::F32_LANES] = cast(a);
1957				let b: [u32; Self::F32_LANES] = cast(b);
1958				for i in 0..Self::F32_LANES {
1959					let m = a[i] as u64 * b[i] as u64;
1960
1961					(lo[i], hi[i]) = (m as u32, (m >> 32) as u32);
1962				}
1963				(cast(lo), cast(hi))
1964			}
1965
1966			#[inline]
1967			fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1968				let mut out = [0.0f32; Self::F32_LANES];
1969				let a: [f32; Self::F32_LANES] = cast(a);
1970				let b: [f32; Self::F32_LANES] = cast(b);
1971				let c: [f32; Self::F32_LANES] = cast(c);
1972
1973				for i in 0..Self::F32_LANES {
1974					out[i] = fma_f32(a[i], b[i], c[i]);
1975				}
1976
1977				cast(out)
1978			}
1979
1980			#[inline]
1981			fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
1982				let mut out = [0.0f32; Self::F32_LANES];
1983
1984				let a: [f32; Self::F32_LANES] = cast(a);
1985				let b: [f32; Self::F32_LANES] = cast(b);
1986				let c: [f32; Self::F32_LANES] = cast(c);
1987
1988				for i in 0..Self::F32_LANES {
1989					out[i] = fma_f32(-a[i], b[i], c[i]);
1990				}
1991
1992				cast(out)
1993			}
1994
1995			#[inline]
1996			fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
1997				let mut a: [f32; Self::F32_LANES] = cast(a);
1998
1999				let mut n = Self::F32_LANES;
2000				while n > 1 {
2001					n /= 2;
2002					for i in 0..n {
2003						a[i] += a[i + n];
2004					}
2005				}
2006
2007				a[0]
2008			}
2009
2010			#[inline]
2011			fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
2012				let mut a: [f32; Self::F32_LANES] = cast(a);
2013
2014				let mut n = Self::F32_LANES;
2015				while n > 1 {
2016					n /= 2;
2017					for i in 0..n {
2018						a[i] *= a[i + n];
2019					}
2020				}
2021
2022				a[0]
2023			}
2024
2025			#[inline]
2026			fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
2027				let mut a: [f32; Self::F32_LANES] = cast(a);
2028
2029				let mut n = Self::F32_LANES;
2030				while n > 1 {
2031					n /= 2;
2032					for i in 0..n {
2033						a[i] = f32::min(a[i], a[i + n]);
2034					}
2035				}
2036
2037				a[0]
2038			}
2039
2040			#[inline]
2041			fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
2042				let mut a: [f32; Self::F32_LANES] = cast(a);
2043
2044				let mut n = Self::F32_LANES;
2045				while n > 1 {
2046					n /= 2;
2047					for i in 0..n {
2048						a[i] = f32::max(a[i], a[i + n]);
2049					}
2050				}
2051
2052				a[0]
2053			}
2054
2055			#[inline]
2056			fn splat_c32s(self, value: c32) -> Self::c32s {
2057				cast([value; Self::C32_LANES])
2058			}
2059
2060			#[inline]
2061			fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
2062				let mut out = [c32::ZERO; Self::C32_LANES];
2063				let a: [c32; Self::C32_LANES] = cast(a);
2064
2065				for i in 0..Self::C32_LANES {
2066					out[i] = c32::new(a[i].re, -a[i].im);
2067				}
2068
2069				cast(out)
2070			}
2071
2072			#[inline]
2073			fn neg_c32s(self, a: Self::c32s) -> Self::c32s {
2074				let mut out = [c32::ZERO; Self::C32_LANES];
2075				let a: [c32; Self::C32_LANES] = cast(a);
2076
2077				for i in 0..Self::C32_LANES {
2078					out[i] = c32::new(-a[i].re, -a[i].im);
2079				}
2080
2081				cast(out)
2082			}
2083
2084			#[inline]
2085			fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
2086				let mut out = [c32::ZERO; Self::C32_LANES];
2087				let a: [c32; Self::C32_LANES] = cast(a);
2088
2089				for i in 0..Self::C32_LANES {
2090					out[i] = c32::new(a[i].im, a[i].re);
2091				}
2092
2093				cast(out)
2094			}
2095
2096			#[inline]
2097			fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
2098				let mut out = [c32::ZERO; Self::C32_LANES];
2099				let a: [c32; Self::C32_LANES] = cast(a);
2100				let b: [c32; Self::C32_LANES] = cast(b);
2101
2102				for i in 0..Self::C32_LANES {
2103					out[i].re = fma_f32(a[i].re, b[i].re, a[i].im * b[i].im);
2104					out[i].im = fma_f32(a[i].re, b[i].im, -(a[i].im * b[i].re));
2105				}
2106
2107				cast(out)
2108			}
2109
2110			#[inline]
2111			fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2112				let mut out = [c32::ZERO; Self::C32_LANES];
2113				let a: [c32; Self::C32_LANES] = cast(a);
2114				let b: [c32; Self::C32_LANES] = cast(b);
2115				let c: [c32; Self::C32_LANES] = cast(c);
2116
2117				for i in 0..Self::C32_LANES {
2118					out[i].re = fma_f32(a[i].re, b[i].re, -fma_f32(a[i].im, b[i].im, -c[i].re));
2119					out[i].im = fma_f32(a[i].re, b[i].im, fma_f32(a[i].im, b[i].re, c[i].im));
2120				}
2121
2122				cast(out)
2123			}
2124
2125			#[inline]
2126			fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2127				let mut out = [c32::ZERO; Self::C32_LANES];
2128				let a: [c32; Self::C32_LANES] = cast(a);
2129				let b: [c32; Self::C32_LANES] = cast(b);
2130				let c: [c32; Self::C32_LANES] = cast(c);
2131
2132				for i in 0..Self::C32_LANES {
2133					out[i].re = fma_f32(a[i].re, b[i].re, fma_f32(a[i].im, b[i].im, c[i].re));
2134					out[i].im = fma_f32(a[i].re, b[i].im, -fma_f32(a[i].im, b[i].re, -c[i].im));
2135				}
2136
2137				cast(out)
2138			}
2139
2140			#[inline]
2141			fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
2142				let mut out = [c32::ZERO; Self::C32_LANES];
2143				let a: [c32; Self::C32_LANES] = cast(a);
2144
2145				for i in 0..Self::C32_LANES {
2146					let x = a[i].re * a[i].re + a[i].im * a[i].im;
2147					out[i].re = x;
2148					out[i].im = x;
2149				}
2150
2151				cast(out)
2152			}
2153
2154			#[inline]
2155			fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
2156				let mut out = [c32::ZERO; Self::C32_LANES];
2157				let a: [c32; Self::C32_LANES] = cast(self.abs_f32s(a));
2158
2159				for i in 0..Self::C32_LANES {
2160					let x = f32::max(a[i].re, a[i].im);
2161					out[i].re = x;
2162					out[i].im = x;
2163				}
2164
2165				cast(out)
2166			}
2167
2168			#[inline]
2169			fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
2170				let mut a: [c32; Self::C32_LANES] = cast(a);
2171
2172				let mut n = Self::C32_LANES;
2173				while n > 1 {
2174					n /= 2;
2175					for i in 0..n {
2176						a[i].re += a[i + n].re;
2177						a[i].im += a[i + n].im;
2178					}
2179				}
2180
2181				a[0]
2182			}
2183
2184			#[inline]
2185			fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
2186				let mut a: [c32; Self::C32_LANES] = cast(a);
2187
2188				let mut n = Self::C32_LANES;
2189				while n > 1 {
2190					n /= 2;
2191					for i in 0..n {
2192						a[i].re = f32::min(a[i].re, a[i + n].re);
2193						a[i].im = f32::min(a[i].im, a[i + n].im);
2194					}
2195				}
2196
2197				a[0]
2198			}
2199
2200			#[inline]
2201			fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
2202				let mut a: [c32; Self::C32_LANES] = cast(a);
2203
2204				let mut n = Self::C32_LANES;
2205				while n > 1 {
2206					n /= 2;
2207					for i in 0..n {
2208						a[i].re = f32::max(a[i].re, a[i + n].re);
2209						a[i].im = f32::max(a[i].im, a[i + n].im);
2210					}
2211				}
2212
2213				a[0]
2214			}
2215
2216			#[inline]
2217			fn rotate_right_u32s(self, a: Self::u32s, amount: usize) -> Self::u32s {
2218				let mut a: [u32; Self::F32_LANES] = cast(a);
2219				let amount = amount % Self::F32_LANES;
2220				a.rotate_right(amount);
2221				cast(a)
2222			}
2223
2224			#[inline]
2225			fn rotate_right_c32s(self, a: Self::c32s, amount: usize) -> Self::c32s {
2226				let mut a: [c32; Self::C32_LANES] = cast(a);
2227				let amount = amount % Self::C32_LANES;
2228				a.rotate_right(amount);
2229				cast(a)
2230			}
2231
2232			#[inline]
2233			fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2234				let mut out = [0.0f64; Self::F64_LANES];
2235				let a: [f64; Self::F64_LANES] = cast(a);
2236				let b: [f64; Self::F64_LANES] = cast(b);
2237				let c: [f64; Self::F64_LANES] = cast(c);
2238
2239				for i in 0..Self::F64_LANES {
2240					out[i] = fma_f64(a[i], b[i], c[i]);
2241				}
2242
2243				cast(out)
2244			}
2245
2246			#[inline]
2247			fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2248				let mut out = [0.0f64; Self::F64_LANES];
2249				let a: [f64; Self::F64_LANES] = cast(a);
2250				let b: [f64; Self::F64_LANES] = cast(b);
2251				let c: [f64; Self::F64_LANES] = cast(c);
2252
2253				for i in 0..Self::F64_LANES {
2254					out[i] = fma_f64(-a[i], b[i], c[i]);
2255				}
2256
2257				cast(out)
2258			}
2259
2260			#[inline]
2261			fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
2262				let mut a: [f64; Self::F64_LANES] = cast(a);
2263
2264				let mut n = Self::F64_LANES;
2265				while n > 1 {
2266					n /= 2;
2267					for i in 0..n {
2268						a[i] += a[i + n];
2269					}
2270				}
2271
2272				a[0]
2273			}
2274
2275			#[inline]
2276			fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
2277				let mut a: [f64; Self::F64_LANES] = cast(a);
2278
2279				let mut n = Self::F64_LANES;
2280				while n > 1 {
2281					n /= 2;
2282					for i in 0..n {
2283						a[i] *= a[i + n];
2284					}
2285				}
2286
2287				a[0]
2288			}
2289
2290			#[inline]
2291			fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
2292				let mut a: [f64; Self::F64_LANES] = cast(a);
2293
2294				let mut n = Self::F64_LANES;
2295				while n > 1 {
2296					n /= 2;
2297					for i in 0..n {
2298						a[i] = f64::min(a[i], a[i + n]);
2299					}
2300				}
2301
2302				a[0]
2303			}
2304
2305			#[inline]
2306			fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
2307				let mut a: [f64; Self::F64_LANES] = cast(a);
2308
2309				let mut n = Self::F64_LANES;
2310				while n > 1 {
2311					n /= 2;
2312					for i in 0..n {
2313						a[i] = f64::max(a[i], a[i + n]);
2314					}
2315				}
2316
2317				a[0]
2318			}
2319
2320			#[inline]
2321			fn splat_c64s(self, value: c64) -> Self::c64s {
2322				cast([value; Self::C64_LANES])
2323			}
2324
2325			#[inline]
2326			fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
2327				let mut out = [c64::ZERO; Self::C64_LANES];
2328				let a: [c64; Self::C64_LANES] = cast(a);
2329
2330				for i in 0..Self::C64_LANES {
2331					out[i] = c64::new(a[i].re, -a[i].im);
2332				}
2333
2334				cast(out)
2335			}
2336
2337			#[inline]
2338			fn neg_c64s(self, a: Self::c64s) -> Self::c64s {
2339				let mut out = [c64::ZERO; Self::C64_LANES];
2340				let a: [c64; Self::C64_LANES] = cast(a);
2341
2342				for i in 0..Self::C64_LANES {
2343					out[i] = c64::new(-a[i].re, -a[i].im);
2344				}
2345
2346				cast(out)
2347			}
2348
2349			#[inline]
2350			fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
2351				let mut out = [c64::ZERO; Self::C64_LANES];
2352				let a: [c64; Self::C64_LANES] = cast(a);
2353
2354				for i in 0..Self::C64_LANES {
2355					out[i] = c64::new(a[i].im, a[i].re);
2356				}
2357
2358				cast(out)
2359			}
2360
2361			#[inline]
2362			fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
2363				let mut out = [c64::ZERO; Self::C64_LANES];
2364				let a: [c64; Self::C64_LANES] = cast(a);
2365				let b: [c64; Self::C64_LANES] = cast(b);
2366
2367				for i in 0..Self::C64_LANES {
2368					out[i].re = fma_f64(a[i].re, b[i].re, a[i].im * b[i].im);
2369					out[i].im = fma_f64(a[i].re, b[i].im, -(a[i].im * b[i].re));
2370				}
2371
2372				cast(out)
2373			}
2374
2375			#[inline]
2376			fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2377				let mut out = [c64::ZERO; Self::C64_LANES];
2378				let a: [c64; Self::C64_LANES] = cast(a);
2379				let b: [c64; Self::C64_LANES] = cast(b);
2380				let c: [c64; Self::C64_LANES] = cast(c);
2381
2382				for i in 0..Self::C64_LANES {
2383					out[i].re = fma_f64(a[i].re, b[i].re, -fma_f64(a[i].im, b[i].im, -c[i].re));
2384					out[i].im = fma_f64(a[i].re, b[i].im, fma_f64(a[i].im, b[i].re, c[i].im));
2385				}
2386
2387				cast(out)
2388			}
2389
2390			#[inline]
2391			fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2392				let mut out = [c64::ZERO; Self::C64_LANES];
2393				let a: [c64; Self::C64_LANES] = cast(a);
2394				let b: [c64; Self::C64_LANES] = cast(b);
2395				let c: [c64; Self::C64_LANES] = cast(c);
2396
2397				for i in 0..Self::C64_LANES {
2398					out[i].re = fma_f64(a[i].re, b[i].re, fma_f64(a[i].im, b[i].im, c[i].re));
2399					out[i].im = fma_f64(a[i].re, b[i].im, -fma_f64(a[i].im, b[i].re, -c[i].im));
2400				}
2401
2402				cast(out)
2403			}
2404
2405			#[inline]
2406			fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
2407				let mut out = [c64::ZERO; Self::C64_LANES];
2408				let a: [c64; Self::C64_LANES] = cast(a);
2409
2410				for i in 0..Self::C64_LANES {
2411					let x = a[i].re * a[i].re + a[i].im * a[i].im;
2412					out[i].re = x;
2413					out[i].im = x;
2414				}
2415
2416				cast(out)
2417			}
2418
2419			#[inline]
2420			fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
2421				let mut out = [c64::ZERO; Self::C64_LANES];
2422				let a: [c64; Self::C64_LANES] = cast(self.abs_f64s(a));
2423
2424				for i in 0..Self::C64_LANES {
2425					let x = f64::max(a[i].re, a[i].im);
2426					out[i].re = x;
2427					out[i].im = x;
2428				}
2429
2430				cast(out)
2431			}
2432
2433			#[inline]
2434			fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
2435				let mut a: [c64; Self::C64_LANES] = cast(a);
2436
2437				let mut n = Self::C64_LANES;
2438				while n > 1 {
2439					n /= 2;
2440					for i in 0..n {
2441						a[i].re += a[i + n].re;
2442						a[i].im += a[i + n].im;
2443					}
2444				}
2445
2446				a[0]
2447			}
2448
2449			#[inline]
2450			fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
2451				let mut a: [c64; Self::C64_LANES] = cast(a);
2452
2453				let mut n = Self::C64_LANES;
2454				while n > 1 {
2455					n /= 2;
2456					for i in 0..n {
2457						a[i].re = f64::min(a[i].re, a[i + n].re);
2458						a[i].im = f64::min(a[i].im, a[i + n].im);
2459					}
2460				}
2461
2462				a[0]
2463			}
2464
2465			#[inline]
2466			fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
2467				let mut a: [c64; Self::C64_LANES] = cast(a);
2468
2469				let mut n = Self::C64_LANES;
2470				while n > 1 {
2471					n /= 2;
2472					for i in 0..n {
2473						a[i].re = f64::max(a[i].re, a[i + n].re);
2474						a[i].im = f64::max(a[i].im, a[i + n].im);
2475					}
2476				}
2477
2478				a[0]
2479			}
2480
2481			#[inline]
2482			fn rotate_right_u64s(self, a: Self::u64s, amount: usize) -> Self::u64s {
2483				let mut a: [u64; Self::F64_LANES] = cast(a);
2484				let amount = amount % Self::F64_LANES;
2485				a.rotate_right(amount);
2486				cast(a)
2487			}
2488
2489			#[inline]
2490			fn rotate_right_c64s(self, a: Self::c64s, amount: usize) -> Self::c64s {
2491				let mut a: [c64; Self::C64_LANES] = cast(a);
2492				let amount = amount % Self::C64_LANES;
2493				a.rotate_right(amount);
2494				cast(a)
2495			}
2496
2497			#[inline]
2498			fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2499				self.mul_add_f32s(a, b, c)
2500			}
2501
2502			#[inline]
2503			fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2504				self.mul_add_f64s(a, b, c)
2505			}
2506
2507			#[inline]
2508			fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2509				self.negate_mul_add_f32s(a, b, c)
2510			}
2511
2512			#[inline]
2513			fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2514				self.negate_mul_add_f64s(a, b, c)
2515			}
2516
2517			#[inline(always)]
2518			fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
2519				let mut out = [0.0_f32; Self::F32_LANES];
2520				let a: [f32; Self::F32_LANES] = cast(a);
2521
2522				for i in 0..Self::F32_LANES {
2523					out[i] = sqrt_f32(a[i]);
2524				}
2525
2526				cast(out)
2527			}
2528			#[inline(always)]
2529			fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
2530				let mut out = [0.0_f64; Self::F64_LANES];
2531				let a: [f64; Self::F64_LANES] = cast(a);
2532
2533				for i in 0..Self::F64_LANES {
2534					out[i] = sqrt_f64(a[i]);
2535				}
2536
2537				cast(out)
2538			}
2539		}
2540	};
2541}
2542
2543scalar_simd!(
2544	Scalar128b, 16, m8x16, i8x16, u8x16, m16x8, i16x8, u16x8, m32x4, f32x4, i32x4, u32x4, m64x2,
2545	f64x2, i64x2, u64x2
2546);
2547scalar_simd!(
2548	Scalar256b, 16, m8x32, i8x32, u8x32, m16x16, i16x16, u16x16, m32x8, f32x8, i32x8, u32x8, m64x4,
2549	f64x4, i64x4, u64x4
2550);
2551scalar_simd!(
2552	Scalar512b, 8, m8x64, i8x64, u8x64, m16x32, i16x32, u16x32, m32x16, f32x16, i32x16, u32x16,
2553	m64x8, f64x8, i64x8, u64x8
2554);
2555
2556impl Default for Scalar {
2557	#[inline]
2558	fn default() -> Self {
2559		Self::new()
2560	}
2561}
2562
2563impl Scalar {
2564	#[inline]
2565	pub fn new() -> Self {
2566		Self
2567	}
2568}
2569
2570macro_rules! impl_primitive_binop {
2571	($func: ident, $op: ident, $ty: ident, $out: ty) => {
2572		paste! {
2573			#[inline(always)]
2574			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
2575				a.$op(b)
2576			}
2577		}
2578	};
2579	(ref $func: ident, $op: ident, $ty: ident, $out: ty) => {
2580		paste! {
2581			#[inline(always)]
2582			fn [<$func _ $ty s>](self, a: Self::[<$ty s>], b: Self::[<$ty s>]) -> Self::[<$out s>] {
2583				a.$op(&b)
2584			}
2585		}
2586	};
2587}
2588
2589macro_rules! primitive_binop {
2590	(ref $func: ident, op $op: ident, $($ty: ident => $out: ty),*) => {
2591		$(impl_primitive_binop!(ref $func, $op, $ty, $out);)*
2592	};
2593	($func: ident, $($ty: ident => $out: ty),*) => {
2594		$(impl_primitive_binop!($func, $func, $ty, $out);)*
2595	};
2596	($func: ident, op $op: ident, $($ty: ident),*) => {
2597		$(impl_primitive_binop!($func, $op, $ty, $ty);)*
2598	};
2599	($func: ident, $($ty: ident),*) => {
2600		$(impl_primitive_binop!($func, $func, $ty, $ty);)*
2601	};
2602}
2603
2604macro_rules! impl_primitive_unop {
2605	($func: ident, $op: ident, $ty: ident, $out: ty) => {
2606		paste! {
2607			#[inline(always)]
2608			fn [<$func _ $ty s>](self, a: Self::[<$ty s>]) -> Self::[<$out s>] {
2609				a.$op()
2610			}
2611		}
2612	};
2613}
2614
2615macro_rules! primitive_unop {
2616	($func: ident, $($ty: ident),*) => {
2617		$(impl_primitive_unop!($func, $func, $ty, $ty);)*
2618	};
2619}
2620
2621macro_rules! splat_primitive {
2622	($ty: ty) => {
2623		paste! {
2624			#[inline]
2625			fn [<splat_ $ty s>](self, value: $ty) -> Self::[<$ty s>] {
2626				value
2627			}
2628		}
2629	};
2630	($($ty: ty),*) => {
2631		$(splat_primitive!($ty);)*
2632	}
2633}
2634
2635impl Seal for Scalar {}
2636impl Simd for Scalar {
2637	type c32s = c32;
2638	type c64s = c64;
2639	type f32s = f32;
2640	type f64s = f64;
2641	type i16s = i16;
2642	type i32s = i32;
2643	type i64s = i64;
2644	type i8s = i8;
2645	type m16s = bool;
2646	type m32s = bool;
2647	type m64s = bool;
2648	type m8s = bool;
2649	type u16s = u16;
2650	type u32s = u32;
2651	type u64s = u64;
2652	type u8s = u8;
2653
2654	const IS_SCALAR: bool = true;
2655	const REGISTER_COUNT: usize = 16;
2656
2657	primitive_binop!(add, c32, f32, c64, f64);
2658
2659	primitive_binop!(add, op wrapping_add, u8, i8, u16, i16, u32, i32, u64, i64);
2660
2661	primitive_binop!(sub, c32, f32, c64, f64);
2662
2663	primitive_binop!(sub, op wrapping_sub, u8, i8, u16, i16, u32, i32, u64, i64);
2664
2665	primitive_binop!(mul, f32, f64);
2666
2667	primitive_binop!(mul, op wrapping_mul, u16, i16, u32, i32, u64, i64);
2668
2669	primitive_binop!(div, f32, f64);
2670
2671	primitive_binop!(and, op bitand, m8, u8, m16, u16, m32, u32, m64, u64);
2672
2673	primitive_binop!(or, op bitor, m8, u8, m16, u16, m32, u32, m64, u64);
2674
2675	primitive_binop!(xor, op bitxor, m8, u8, m16, u16, m32, u32, m64, u64);
2676
2677	primitive_binop!(ref equal, op eq, m8 => m8, u8 => m8, m16 => m16, u16 => m16, m32 => m32, u32 => m32, m64 => m64, u64 => m64, c32 => m32, f32 => m32, c64 => m64, f64 => m64);
2678
2679	primitive_binop!(ref greater_than, op gt, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
2680
2681	primitive_binop!(ref greater_than_or_equal, op ge, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
2682
2683	primitive_binop!(ref less_than, op lt, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
2684
2685	primitive_binop!(ref less_than_or_equal, op le, u8 => m8, i8 => m8, u16 => m16, i16 => m16, u32 => m32, i32 => m32, u64 => m64, i64 => m64, f32 => m32, f64 => m64);
2686
2687	primitive_binop!(min, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
2688
2689	primitive_binop!(max, u8, i8, u16, i16, u32, i32, u64, i64, f32, f64);
2690
2691	primitive_unop!(neg, c32, c64, f32, f64);
2692
2693	primitive_unop!(not, m8, u8, m16, u16, m32, u32, m64, u64);
2694
2695	splat_primitive!(u8, i8, u16, i16, u32, i32, u64, i64, c32, f32, c64, f64);
2696
2697	#[inline]
2698	fn abs2_c32s(self, a: Self::c32s) -> Self::c32s {
2699		let norm2 = a.re * a.re + a.im * a.im;
2700		c32::new(norm2, norm2)
2701	}
2702
2703	#[inline]
2704	fn abs2_c64s(self, a: Self::c64s) -> Self::c64s {
2705		let norm2 = a.re * a.re + a.im * a.im;
2706		c64::new(norm2, norm2)
2707	}
2708
2709	#[inline(always)]
2710	fn abs_max_c32s(self, a: Self::c32s) -> Self::c32s {
2711		let re = if a.re > a.im { a.re } else { a.im };
2712		let im = re;
2713		Complex { re, im }
2714	}
2715
2716	#[inline(always)]
2717	fn abs_max_c64s(self, a: Self::c64s) -> Self::c64s {
2718		let re = if a.re > a.im { a.re } else { a.im };
2719		let im = re;
2720		Complex { re, im }
2721	}
2722
2723	#[inline]
2724	fn conj_c32s(self, a: Self::c32s) -> Self::c32s {
2725		a.conj()
2726	}
2727
2728	#[inline]
2729	fn conj_c64s(self, a: Self::c64s) -> Self::c64s {
2730		a.conj()
2731	}
2732
2733	#[inline]
2734	fn conj_mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2735		let re = fma_f32(a.re, b.re, fma_f32(a.im, b.im, c.re));
2736		let im = fma_f32(a.re, b.im, -fma_f32(a.im, b.re, -c.im));
2737		Complex { re, im }
2738	}
2739
2740	#[inline]
2741	fn conj_mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2742		let re = fma_f64(a.re, b.re, fma_f64(a.im, b.im, c.re));
2743		let im = fma_f64(a.re, b.im, -fma_f64(a.im, b.re, -c.im));
2744		Complex { re, im }
2745	}
2746
2747	#[inline]
2748	fn conj_mul_add_e_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2749		a.conj() * b + c
2750	}
2751
2752	#[inline]
2753	fn conj_mul_add_e_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2754		a.conj() * b + c
2755	}
2756
2757	#[inline]
2758	fn conj_mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
2759		let re = fma_f32(a.re, b.re, a.im * b.im);
2760		let im = fma_f32(a.re, b.im, -(a.im * b.re));
2761		Complex { re, im }
2762	}
2763
2764	#[inline]
2765	fn conj_mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
2766		let re = fma_f64(a.re, b.re, a.im * b.im);
2767		let im = fma_f64(a.re, b.im, -(a.im * b.re));
2768		Complex { re, im }
2769	}
2770
2771	#[inline]
2772	fn conj_mul_e_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
2773		a.conj() * b
2774	}
2775
2776	#[inline]
2777	fn conj_mul_e_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
2778		a.conj() * b
2779	}
2780
2781	#[inline(always)]
2782	fn first_true_m32s(self, mask: Self::m32s) -> usize {
2783		if mask { 0 } else { 1 }
2784	}
2785
2786	#[inline(always)]
2787	fn first_true_m64s(self, mask: Self::m64s) -> usize {
2788		if mask { 0 } else { 1 }
2789	}
2790
2791	#[inline(always)]
2792	unsafe fn mask_load_ptr_c32s(self, mask: MemMask<Self::m32s>, ptr: *const c32) -> Self::c32s {
2793		if mask.mask { *ptr } else { core::mem::zeroed() }
2794	}
2795
2796	#[inline(always)]
2797	unsafe fn mask_load_ptr_c64s(self, mask: MemMask<Self::m64s>, ptr: *const c64) -> Self::c64s {
2798		if mask.mask { *ptr } else { core::mem::zeroed() }
2799	}
2800
2801	#[inline(always)]
2802	unsafe fn mask_load_ptr_u32s(self, mask: MemMask<Self::m32s>, ptr: *const u32) -> Self::u32s {
2803		if mask.mask { *ptr } else { 0 }
2804	}
2805
2806	#[inline(always)]
2807	unsafe fn mask_load_ptr_u64s(self, mask: MemMask<Self::m64s>, ptr: *const u64) -> Self::u64s {
2808		if mask.mask { *ptr } else { 0 }
2809	}
2810
2811	#[inline(always)]
2812	unsafe fn mask_store_ptr_c32s(
2813		self,
2814		mask: MemMask<Self::m32s>,
2815		ptr: *mut c32,
2816		values: Self::c32s,
2817	) {
2818		if mask.mask {
2819			*ptr = values
2820		}
2821	}
2822
2823	#[inline(always)]
2824	unsafe fn mask_store_ptr_c64s(
2825		self,
2826		mask: MemMask<Self::m64s>,
2827		ptr: *mut c64,
2828		values: Self::c64s,
2829	) {
2830		if mask.mask {
2831			*ptr = values
2832		}
2833	}
2834
2835	#[inline(always)]
2836	unsafe fn mask_store_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *mut u8, values: Self::u8s) {
2837		if mask.mask {
2838			*ptr = values
2839		}
2840	}
2841
2842	#[inline(always)]
2843	unsafe fn mask_store_ptr_u16s(
2844		self,
2845		mask: MemMask<Self::m16s>,
2846		ptr: *mut u16,
2847		values: Self::u16s,
2848	) {
2849		if mask.mask {
2850			*ptr = values
2851		}
2852	}
2853
2854	#[inline(always)]
2855	unsafe fn mask_store_ptr_u32s(
2856		self,
2857		mask: MemMask<Self::m32s>,
2858		ptr: *mut u32,
2859		values: Self::u32s,
2860	) {
2861		if mask.mask {
2862			*ptr = values
2863		}
2864	}
2865
2866	#[inline(always)]
2867	unsafe fn mask_store_ptr_u64s(
2868		self,
2869		mask: MemMask<Self::m64s>,
2870		ptr: *mut u64,
2871		values: Self::u64s,
2872	) {
2873		if mask.mask {
2874			*ptr = values
2875		}
2876	}
2877
2878	#[inline]
2879	fn mul_add_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2880		let re = fma_f32(a.re, b.re, -fma_f32(a.im, b.im, -c.re));
2881		let im = fma_f32(a.re, b.im, fma_f32(a.im, b.re, c.im));
2882		Complex { re, im }
2883	}
2884
2885	#[inline]
2886	fn mul_add_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2887		let re = fma_f64(a.re, b.re, -fma_f64(a.im, b.im, -c.re));
2888		let im = fma_f64(a.re, b.im, fma_f64(a.im, b.re, c.im));
2889		Complex { re, im }
2890	}
2891
2892	#[inline]
2893	fn mul_add_e_c32s(self, a: Self::c32s, b: Self::c32s, c: Self::c32s) -> Self::c32s {
2894		a * b + c
2895	}
2896
2897	#[inline]
2898	fn mul_add_e_c64s(self, a: Self::c64s, b: Self::c64s, c: Self::c64s) -> Self::c64s {
2899		a * b + c
2900	}
2901
2902	#[inline(always)]
2903	fn mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2904		a * b + c
2905	}
2906
2907	#[inline(always)]
2908	fn mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2909		a * b + c
2910	}
2911
2912	#[inline]
2913	fn mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2914		fma_f32(a, b, c)
2915	}
2916
2917	#[inline]
2918	fn mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2919		fma_f64(a, b, c)
2920	}
2921
2922	#[inline]
2923	fn negate_mul_add_e_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2924		c - a * b
2925	}
2926
2927	#[inline]
2928	fn negate_mul_add_e_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2929		c - a * b
2930	}
2931
2932	#[inline]
2933	fn negate_mul_add_f32s(self, a: Self::f32s, b: Self::f32s, c: Self::f32s) -> Self::f32s {
2934		fma_f32(-a, b, c)
2935	}
2936
2937	#[inline]
2938	fn negate_mul_add_f64s(self, a: Self::f64s, b: Self::f64s, c: Self::f64s) -> Self::f64s {
2939		fma_f64(-a, b, c)
2940	}
2941
2942	#[inline]
2943	fn mul_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
2944		let re = fma_f32(a.re, b.re, -(a.im * b.im));
2945		let im = fma_f32(a.re, b.im, a.im * b.re);
2946		Complex { re, im }
2947	}
2948
2949	#[inline]
2950	fn mul_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
2951		let re = fma_f64(a.re, b.re, -(a.im * b.im));
2952		let im = fma_f64(a.re, b.im, a.im * b.re);
2953		Complex { re, im }
2954	}
2955
2956	#[inline]
2957	fn mul_e_c32s(self, a: Self::c32s, b: Self::c32s) -> Self::c32s {
2958		a * b
2959	}
2960
2961	#[inline]
2962	fn mul_e_c64s(self, a: Self::c64s, b: Self::c64s) -> Self::c64s {
2963		a * b
2964	}
2965
2966	#[inline]
2967	fn partial_load_c64s(self, slice: &[c64]) -> Self::c64s {
2968		if let Some((head, _)) = slice.split_first() {
2969			*head
2970		} else {
2971			c64 { re: 0.0, im: 0.0 }
2972		}
2973	}
2974
2975	#[inline]
2976	fn partial_load_u32s(self, slice: &[u32]) -> Self::u32s {
2977		if let Some((head, _)) = slice.split_first() {
2978			*head
2979		} else {
2980			0
2981		}
2982	}
2983
2984	#[inline]
2985	fn partial_load_u64s(self, slice: &[u64]) -> Self::u64s {
2986		if let Some((head, _)) = slice.split_first() {
2987			*head
2988		} else {
2989			0
2990		}
2991	}
2992
2993	#[inline]
2994	fn partial_store_c64s(self, slice: &mut [c64], values: Self::c64s) {
2995		if let Some((head, _)) = slice.split_first_mut() {
2996			*head = values;
2997		}
2998	}
2999
3000	#[inline]
3001	fn partial_store_u32s(self, slice: &mut [u32], values: Self::u32s) {
3002		if let Some((head, _)) = slice.split_first_mut() {
3003			*head = values;
3004		}
3005	}
3006
3007	#[inline]
3008	fn partial_store_u64s(self, slice: &mut [u64], values: Self::u64s) {
3009		if let Some((head, _)) = slice.split_first_mut() {
3010			*head = values;
3011		}
3012	}
3013
3014	#[inline(always)]
3015	fn reduce_max_c32s(self, a: Self::c32s) -> c32 {
3016		a
3017	}
3018
3019	#[inline(always)]
3020	fn reduce_max_c64s(self, a: Self::c64s) -> c64 {
3021		a
3022	}
3023
3024	#[inline]
3025	fn reduce_max_f32s(self, a: Self::f32s) -> f32 {
3026		a
3027	}
3028
3029	#[inline]
3030	fn reduce_max_f64s(self, a: Self::f64s) -> f64 {
3031		a
3032	}
3033
3034	#[inline(always)]
3035	fn reduce_min_c32s(self, a: Self::c32s) -> c32 {
3036		a
3037	}
3038
3039	#[inline(always)]
3040	fn reduce_min_c64s(self, a: Self::c64s) -> c64 {
3041		a
3042	}
3043
3044	#[inline]
3045	fn reduce_min_f32s(self, a: Self::f32s) -> f32 {
3046		a
3047	}
3048
3049	#[inline]
3050	fn reduce_min_f64s(self, a: Self::f64s) -> f64 {
3051		a
3052	}
3053
3054	#[inline]
3055	fn reduce_product_f32s(self, a: Self::f32s) -> f32 {
3056		a
3057	}
3058
3059	#[inline]
3060	fn reduce_product_f64s(self, a: Self::f64s) -> f64 {
3061		a
3062	}
3063
3064	#[inline]
3065	fn reduce_sum_c32s(self, a: Self::c32s) -> c32 {
3066		a
3067	}
3068
3069	#[inline]
3070	fn reduce_sum_c64s(self, a: Self::c64s) -> c64 {
3071		a
3072	}
3073
3074	#[inline]
3075	fn reduce_sum_f32s(self, a: Self::f32s) -> f32 {
3076		a
3077	}
3078
3079	#[inline]
3080	fn reduce_sum_f64s(self, a: Self::f64s) -> f64 {
3081		a
3082	}
3083
3084	#[inline(always)]
3085	fn rotate_right_c32s(self, a: Self::c32s, _amount: usize) -> Self::c32s {
3086		a
3087	}
3088
3089	#[inline(always)]
3090	fn rotate_right_c64s(self, a: Self::c64s, _amount: usize) -> Self::c64s {
3091		a
3092	}
3093
3094	#[inline(always)]
3095	fn rotate_right_u32s(self, a: Self::u32s, _amount: usize) -> Self::u32s {
3096		a
3097	}
3098
3099	#[inline(always)]
3100	fn rotate_right_u64s(self, a: Self::u64s, _amount: usize) -> Self::u64s {
3101		a
3102	}
3103
3104	#[inline]
3105	fn select_u32s(
3106		self,
3107		mask: Self::m32s,
3108		if_true: Self::u32s,
3109		if_false: Self::u32s,
3110	) -> Self::u32s {
3111		if mask { if_true } else { if_false }
3112	}
3113
3114	#[inline]
3115	fn select_u64s(
3116		self,
3117		mask: Self::m64s,
3118		if_true: Self::u64s,
3119		if_false: Self::u64s,
3120	) -> Self::u64s {
3121		if mask { if_true } else { if_false }
3122	}
3123
3124	#[inline]
3125	fn swap_re_im_c32s(self, a: Self::c32s) -> Self::c32s {
3126		c32 { re: a.im, im: a.re }
3127	}
3128
3129	fn swap_re_im_c64s(self, a: Self::c64s) -> Self::c64s {
3130		c64 { re: a.im, im: a.re }
3131	}
3132
3133	#[inline]
3134	fn vectorize<Op: WithSimd>(self, op: Op) -> Op::Output {
3135		op.with_simd(self)
3136	}
3137
3138	#[inline]
3139	fn widening_mul_u32s(self, a: Self::u32s, b: Self::u32s) -> (Self::u32s, Self::u32s) {
3140		let c = a as u64 * b as u64;
3141		let lo = c as u32;
3142		let hi = (c >> 32) as u32;
3143		(lo, hi)
3144	}
3145
3146	#[inline]
3147	fn wrapping_dyn_shl_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
3148		a.wrapping_shl(amount)
3149	}
3150
3151	#[inline]
3152	fn wrapping_dyn_shr_u32s(self, a: Self::u32s, amount: Self::u32s) -> Self::u32s {
3153		a.wrapping_shr(amount)
3154	}
3155
3156	unsafe fn mask_load_ptr_u8s(self, mask: MemMask<Self::m8s>, ptr: *const u8) -> Self::u8s {
3157		if mask.mask { *ptr } else { 0 }
3158	}
3159
3160	unsafe fn mask_load_ptr_u16s(self, mask: MemMask<Self::m16s>, ptr: *const u16) -> Self::u16s {
3161		if mask.mask { *ptr } else { 0 }
3162	}
3163
3164	#[inline(always)]
3165	fn sqrt_f32s(self, a: Self::f32s) -> Self::f32s {
3166		sqrt_f32(a)
3167	}
3168
3169	#[inline(always)]
3170	fn sqrt_f64s(self, a: Self::f64s) -> Self::f64s {
3171		sqrt_f64(a)
3172	}
3173}
3174
3175#[inline(always)]
3176unsafe fn split_slice<T, U>(slice: &[T]) -> (&[U], &[T]) {
3177	assert_eq!(core::mem::size_of::<U>() % core::mem::size_of::<T>(), 0);
3178	assert_eq!(core::mem::align_of::<U>(), core::mem::align_of::<T>());
3179
3180	let chunk_size = core::mem::size_of::<U>() / core::mem::size_of::<T>();
3181
3182	let len = slice.len();
3183	let data = slice.as_ptr();
3184
3185	let div = len / chunk_size;
3186	let rem = len % chunk_size;
3187	(
3188		from_raw_parts(data as *const U, div),
3189		from_raw_parts(data.add(len - rem), rem),
3190	)
3191}
3192
3193#[inline(always)]
3194unsafe fn split_mut_slice<T, U>(slice: &mut [T]) -> (&mut [U], &mut [T]) {
3195	assert_eq!(core::mem::size_of::<U>() % core::mem::size_of::<T>(), 0);
3196	assert_eq!(core::mem::align_of::<U>(), core::mem::align_of::<T>());
3197
3198	let chunk_size = core::mem::size_of::<U>() / core::mem::size_of::<T>();
3199
3200	let len = slice.len();
3201	let data = slice.as_mut_ptr();
3202
3203	let div = len / chunk_size;
3204	let rem = len % chunk_size;
3205	(
3206		from_raw_parts_mut(data as *mut U, div),
3207		from_raw_parts_mut(data.add(len - rem), rem),
3208	)
3209}
3210
3211#[inline(always)]
3212unsafe fn rsplit_slice<T, U>(slice: &[T]) -> (&[T], &[U]) {
3213	assert_eq!(core::mem::size_of::<U>() % core::mem::size_of::<T>(), 0);
3214	assert_eq!(core::mem::align_of::<U>(), core::mem::align_of::<T>());
3215
3216	let chunk_size = core::mem::size_of::<U>() / core::mem::size_of::<T>();
3217
3218	let len = slice.len();
3219	let data = slice.as_ptr();
3220
3221	let div = len / chunk_size;
3222	let rem = len % chunk_size;
3223	(
3224		from_raw_parts(data, rem),
3225		from_raw_parts(data.add(rem) as *const U, div),
3226	)
3227}
3228
3229#[inline(always)]
3230unsafe fn rsplit_mut_slice<T, U>(slice: &mut [T]) -> (&mut [T], &mut [U]) {
3231	assert_eq!(core::mem::size_of::<U>() % core::mem::size_of::<T>(), 0);
3232	assert_eq!(core::mem::align_of::<U>(), core::mem::align_of::<T>());
3233
3234	let chunk_size = core::mem::size_of::<U>() / core::mem::size_of::<T>();
3235
3236	let len = slice.len();
3237	let data = slice.as_mut_ptr();
3238
3239	let div = len / chunk_size;
3240	let rem = len % chunk_size;
3241	(
3242		from_raw_parts_mut(data, rem),
3243		from_raw_parts_mut(data.add(rem) as *mut U, div),
3244	)
3245}
3246
3247match_cfg!(
3248	item,
3249	match cfg!() {
3250		const { any(target_arch = "x86", target_arch = "x86_64") } => {
3251			pub use x86::Arch;
3252		},
3253		const { target_arch = "aarch64" } => {
3254			pub use aarch64::Arch;
3255		},
3256		const { target_arch = "wasm32" } => {
3257			pub use wasm::Arch;
3258		},
3259		_ => {
3260			#[derive(Debug, Clone, Copy)]
3261			#[non_exhaustive]
3262			pub enum Arch {
3263				Scalar,
3264			}
3265
3266			impl Arch {
3267				#[inline(always)]
3268				pub fn new() -> Self {
3269					Self::Scalar
3270				}
3271
3272				#[inline(always)]
3273				pub fn dispatch<Op: WithSimd>(self, op: Op) -> Op::Output {
3274					op.with_simd(Scalar)
3275				}
3276			}
3277			impl Default for Arch {
3278				#[inline]
3279				fn default() -> Self {
3280					Self::new()
3281				}
3282			}
3283		},
3284	}
3285);
3286
3287#[doc(hidden)]
3288pub struct CheckSameSize<T, U>(PhantomData<(T, U)>);
3289impl<T, U> CheckSameSize<T, U> {
3290	pub const VALID: () = {
3291		assert!(core::mem::size_of::<T>() == core::mem::size_of::<U>());
3292	};
3293}
3294
3295#[doc(hidden)]
3296pub struct CheckSizeLessThanOrEqual<T, U>(PhantomData<(T, U)>);
3297impl<T, U> CheckSizeLessThanOrEqual<T, U> {
3298	pub const VALID: () = {
3299		assert!(core::mem::size_of::<T>() <= core::mem::size_of::<U>());
3300	};
3301}
3302
3303#[macro_export]
3304macro_rules! static_assert_same_size {
3305	($t: ty, $u: ty) => {
3306		let _ = $crate::CheckSameSize::<$t, $u>::VALID;
3307	};
3308}
3309#[macro_export]
3310macro_rules! static_assert_size_less_than_or_equal {
3311	($t: ty, $u: ty) => {
3312		let _ = $crate::CheckSizeLessThanOrEqual::<$t, $u>::VALID;
3313	};
3314}
3315
3316/// Safe transmute function.
3317///
3318/// This function asserts at compile time that the two types have the same size.
3319#[inline(always)]
3320pub const fn cast<T: NoUninit, U: AnyBitPattern>(value: T) -> U {
3321	static_assert_same_size!(T, U);
3322	let ptr = &raw const value as *const U;
3323	unsafe { ptr.read_unaligned() }
3324}
3325
3326/// Safe lossy transmute function, where the destination type may be smaller than the source type.
3327///
3328/// This property is checked at compile time.
3329#[inline(always)]
3330pub const fn cast_lossy<T: NoUninit, U: AnyBitPattern>(value: T) -> U {
3331	static_assert_size_less_than_or_equal!(U, T);
3332	let value = core::mem::ManuallyDrop::new(value);
3333	let ptr = &raw const value as *const U;
3334	unsafe { ptr.read_unaligned() }
3335}
3336
3337/// Splits a slice into chunks of equal size (known at compile time).
3338///
3339/// Returns the chunks and the remaining section of the input slice.
3340#[inline(always)]
3341pub fn as_arrays<const N: usize, T>(slice: &[T]) -> (&[[T; N]], &[T]) {
3342	let n = slice.len();
3343	let mid_div_n = n / N;
3344	let mid = mid_div_n * N;
3345	let ptr = slice.as_ptr();
3346	unsafe {
3347		(
3348			from_raw_parts(ptr as *const [T; N], mid_div_n),
3349			from_raw_parts(ptr.add(mid), n - mid),
3350		)
3351	}
3352}
3353
3354/// Splits a slice into chunks of equal size (known at compile time).
3355///
3356/// Returns the chunks and the remaining section of the input slice.
3357#[inline(always)]
3358pub fn as_arrays_mut<const N: usize, T>(slice: &mut [T]) -> (&mut [[T; N]], &mut [T]) {
3359	let n = slice.len();
3360	let mid_div_n = n / N;
3361	let mid = mid_div_n * N;
3362	let ptr = slice.as_mut_ptr();
3363	unsafe {
3364		(
3365			from_raw_parts_mut(ptr as *mut [T; N], mid_div_n),
3366			from_raw_parts_mut(ptr.add(mid), n - mid),
3367		)
3368	}
3369}
3370
3371/// Platform dependent intrinsics.
3372pub mod core_arch;
3373
3374#[allow(unused_macros)]
3375macro_rules! inherit {
3376    ({$(
3377        $(#[$attr: meta])*
3378        $(unsafe $($placeholder: lifetime)?)?
3379        fn $func: ident(self
3380            $(,$arg: ident: $ty: ty)* $(,)?
3381        ) $(-> $ret: ty)?;
3382    )*}) => {
3383        $(
3384            $(#[$attr])*
3385            #[inline(always)]
3386            $(unsafe $($placeholder)?)? fn $func (self, $($arg: $ty,)*) $(-> $ret)? {
3387                (*self).$func ($($arg,)*)
3388            }
3389        )*
3390    };
3391}
3392
3393#[allow(unused_macros)]
3394macro_rules! inherit_x2 {
3395    ($base: expr, {$(
3396        $(#[$attr: meta])*
3397        $(unsafe $($placeholder: lifetime)?)?
3398        fn $func: ident ($self: ident
3399            $(,$arg: ident: $ty: ty)* $(,)?
3400        ) $(-> $ret: ty)?;
3401    )*}) => {
3402        $(
3403            $(#[$attr])*
3404            #[inline(always)]
3405            $(unsafe $($placeholder)?)? fn $func ($self, $($arg: $ty,)*) $(-> $ret)? {
3406            	$(let $arg: [_; 2] = cast!($arg);)*
3407                cast!([($base).$func ($($arg[0],)*), ($base).$func ($($arg[1],)*)])
3408            }
3409        )*
3410    };
3411
3412    ($base: expr, splat, {$(
3413        $(#[$attr: meta])*
3414        $(unsafe $($placeholder: lifetime)?)?
3415        fn $func: ident ($self: ident
3416            $(,$arg: ident: $ty: ty)* $(,)?
3417        ) $(-> $ret: ty)?;
3418    )*}) => {
3419        $(
3420            $(#[$attr])*
3421            #[inline(always)]
3422            $(unsafe $($placeholder)?)? fn $func ($self, $($arg: $ty,)*) $(-> $ret)? {
3423                cast!([($base).$func ($($arg,)*), ($base).$func ($($arg,)*)])
3424            }
3425        )*
3426    };
3427
3428    ($base: expr, wide, {$(
3429        $(#[$attr: meta])*
3430        $(unsafe $($placeholder: lifetime)?)?
3431        fn $func: ident ($self: ident
3432            $(,$arg: ident: $ty: ty)* $(,)?
3433        ) $(-> $ret: ty)?;
3434    )*}) => {
3435        $(
3436            $(#[$attr])*
3437            #[inline(always)]
3438            $(unsafe $($placeholder)?)? fn $func ($self, $($arg: $ty,)*) $(-> $ret)? {
3439            	$(let $arg: [_; 2] = cast!($arg);)*
3440                let (r0, r1) = ($base).$func ($($arg[0],)*); let (s0, s1) = ($base).$func ($($arg[1],)*);
3441                (cast!([r0, s0]), cast!([r1, s1]))
3442            }
3443        )*
3444    };
3445}
3446
3447#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
3448#[cfg_attr(docsrs, doc(cfg(any(target_arch = "x86", target_arch = "x86_64"))))]
3449/// Low level x86 API.
3450pub mod x86;
3451
3452#[cfg(target_arch = "wasm32")]
3453#[cfg_attr(docsrs, doc(cfg(target_arch = "wasm32")))]
3454/// Low level wasm API.
3455pub mod wasm;
3456
3457#[cfg(target_arch = "aarch64")]
3458#[cfg_attr(docsrs, doc(cfg(target_arch = "aarch64")))]
3459/// Low level aarch64 API.
3460pub mod aarch64;
3461
3462/// Mask type with 8 bits. Its bit pattern is either all ones or all zeros. Unsafe code must not
3463/// depend on this, however.
3464#[derive(Copy, Clone, PartialEq, Eq, Default)]
3465#[repr(transparent)]
3466pub struct m8(u8);
3467/// Mask type with 16 bits. Its bit pattern is either all ones or all zeros. Unsafe code must not
3468/// depend on this, however.
3469#[derive(Copy, Clone, PartialEq, Eq, Default)]
3470#[repr(transparent)]
3471pub struct m16(u16);
3472/// Mask type with 32 bits. Its bit pattern is either all ones or all zeros. Unsafe code must not
3473/// depend on this, however.
3474#[derive(Copy, Clone, PartialEq, Eq, Default)]
3475#[repr(transparent)]
3476pub struct m32(u32);
3477/// Mask type with 64 bits. Its bit pattern is either all ones or all zeros. Unsafe code must not
3478/// depend on this, however.
3479#[derive(Copy, Clone, PartialEq, Eq, Default)]
3480#[repr(transparent)]
3481pub struct m64(u64);
3482
3483/// Bitmask type for 8 elements, used for mask operations on AVX512.
3484#[derive(Copy, Clone, PartialEq, Eq)]
3485#[repr(transparent)]
3486pub struct b8(pub u8);
3487/// Bitmask type for 16 elements, used for mask operations on AVX512.
3488#[derive(Copy, Clone, PartialEq, Eq)]
3489#[repr(transparent)]
3490pub struct b16(pub u16);
3491/// Bitmask type for 32 elements, used for mask operations on AVX512.
3492#[derive(Copy, Clone, PartialEq, Eq)]
3493#[repr(transparent)]
3494pub struct b32(pub u32);
3495/// Bitmask type for 64 elements, used for mask operations on AVX512.
3496#[derive(Copy, Clone, PartialEq, Eq)]
3497#[repr(transparent)]
3498pub struct b64(pub u64);
3499
3500impl core::ops::Not for b8 {
3501	type Output = b8;
3502
3503	#[inline(always)]
3504	fn not(self) -> Self::Output {
3505		b8(!self.0)
3506	}
3507}
3508impl core::ops::BitAnd for b8 {
3509	type Output = b8;
3510
3511	#[inline(always)]
3512	fn bitand(self, rhs: Self) -> Self::Output {
3513		b8(self.0 & rhs.0)
3514	}
3515}
3516impl core::ops::BitOr for b8 {
3517	type Output = b8;
3518
3519	#[inline(always)]
3520	fn bitor(self, rhs: Self) -> Self::Output {
3521		b8(self.0 | rhs.0)
3522	}
3523}
3524impl core::ops::BitXor for b8 {
3525	type Output = b8;
3526
3527	#[inline(always)]
3528	fn bitxor(self, rhs: Self) -> Self::Output {
3529		b8(self.0 ^ rhs.0)
3530	}
3531}
3532
3533impl core::ops::Not for m8 {
3534	type Output = m8;
3535
3536	#[inline(always)]
3537	fn not(self) -> Self::Output {
3538		m8(!self.0)
3539	}
3540}
3541impl core::ops::BitAnd for m8 {
3542	type Output = m8;
3543
3544	#[inline(always)]
3545	fn bitand(self, rhs: Self) -> Self::Output {
3546		m8(self.0 & rhs.0)
3547	}
3548}
3549impl core::ops::BitOr for m8 {
3550	type Output = m8;
3551
3552	#[inline(always)]
3553	fn bitor(self, rhs: Self) -> Self::Output {
3554		m8(self.0 | rhs.0)
3555	}
3556}
3557impl core::ops::BitXor for m8 {
3558	type Output = m8;
3559
3560	#[inline(always)]
3561	fn bitxor(self, rhs: Self) -> Self::Output {
3562		m8(self.0 ^ rhs.0)
3563	}
3564}
3565
3566impl core::ops::Not for m16 {
3567	type Output = m16;
3568
3569	#[inline(always)]
3570	fn not(self) -> Self::Output {
3571		m16(!self.0)
3572	}
3573}
3574impl core::ops::BitAnd for m16 {
3575	type Output = m16;
3576
3577	#[inline(always)]
3578	fn bitand(self, rhs: Self) -> Self::Output {
3579		m16(self.0 & rhs.0)
3580	}
3581}
3582impl core::ops::BitOr for m16 {
3583	type Output = m16;
3584
3585	#[inline(always)]
3586	fn bitor(self, rhs: Self) -> Self::Output {
3587		m16(self.0 | rhs.0)
3588	}
3589}
3590impl core::ops::BitXor for m16 {
3591	type Output = m16;
3592
3593	#[inline(always)]
3594	fn bitxor(self, rhs: Self) -> Self::Output {
3595		m16(self.0 ^ rhs.0)
3596	}
3597}
3598
3599impl core::ops::Not for m32 {
3600	type Output = m32;
3601
3602	#[inline(always)]
3603	fn not(self) -> Self::Output {
3604		m32(!self.0)
3605	}
3606}
3607impl core::ops::BitAnd for m32 {
3608	type Output = m32;
3609
3610	#[inline(always)]
3611	fn bitand(self, rhs: Self) -> Self::Output {
3612		m32(self.0 & rhs.0)
3613	}
3614}
3615impl core::ops::BitOr for m32 {
3616	type Output = m32;
3617
3618	#[inline(always)]
3619	fn bitor(self, rhs: Self) -> Self::Output {
3620		m32(self.0 | rhs.0)
3621	}
3622}
3623impl core::ops::BitXor for m32 {
3624	type Output = m32;
3625
3626	#[inline(always)]
3627	fn bitxor(self, rhs: Self) -> Self::Output {
3628		m32(self.0 ^ rhs.0)
3629	}
3630}
3631
3632impl core::ops::Not for m64 {
3633	type Output = m64;
3634
3635	#[inline(always)]
3636	fn not(self) -> Self::Output {
3637		m64(!self.0)
3638	}
3639}
3640impl core::ops::BitAnd for m64 {
3641	type Output = m64;
3642
3643	#[inline(always)]
3644	fn bitand(self, rhs: Self) -> Self::Output {
3645		m64(self.0 & rhs.0)
3646	}
3647}
3648impl core::ops::BitOr for m64 {
3649	type Output = m64;
3650
3651	#[inline(always)]
3652	fn bitor(self, rhs: Self) -> Self::Output {
3653		m64(self.0 | rhs.0)
3654	}
3655}
3656impl core::ops::BitXor for m64 {
3657	type Output = m64;
3658
3659	#[inline(always)]
3660	fn bitxor(self, rhs: Self) -> Self::Output {
3661		m64(self.0 ^ rhs.0)
3662	}
3663}
3664
3665impl core::ops::Not for b16 {
3666	type Output = b16;
3667
3668	#[inline(always)]
3669	fn not(self) -> Self::Output {
3670		b16(!self.0)
3671	}
3672}
3673impl core::ops::BitAnd for b16 {
3674	type Output = b16;
3675
3676	#[inline(always)]
3677	fn bitand(self, rhs: Self) -> Self::Output {
3678		b16(self.0 & rhs.0)
3679	}
3680}
3681impl core::ops::BitOr for b16 {
3682	type Output = b16;
3683
3684	#[inline(always)]
3685	fn bitor(self, rhs: Self) -> Self::Output {
3686		b16(self.0 | rhs.0)
3687	}
3688}
3689impl core::ops::BitXor for b16 {
3690	type Output = b16;
3691
3692	#[inline(always)]
3693	fn bitxor(self, rhs: Self) -> Self::Output {
3694		b16(self.0 ^ rhs.0)
3695	}
3696}
3697
3698impl core::ops::Not for b32 {
3699	type Output = b32;
3700
3701	#[inline(always)]
3702	fn not(self) -> Self::Output {
3703		b32(!self.0)
3704	}
3705}
3706impl core::ops::BitAnd for b32 {
3707	type Output = b32;
3708
3709	#[inline(always)]
3710	fn bitand(self, rhs: Self) -> Self::Output {
3711		b32(self.0 & rhs.0)
3712	}
3713}
3714impl core::ops::BitOr for b32 {
3715	type Output = b32;
3716
3717	#[inline(always)]
3718	fn bitor(self, rhs: Self) -> Self::Output {
3719		b32(self.0 | rhs.0)
3720	}
3721}
3722impl core::ops::BitXor for b32 {
3723	type Output = b32;
3724
3725	#[inline(always)]
3726	fn bitxor(self, rhs: Self) -> Self::Output {
3727		b32(self.0 ^ rhs.0)
3728	}
3729}
3730
3731impl core::ops::Not for b64 {
3732	type Output = b64;
3733
3734	#[inline(always)]
3735	fn not(self) -> Self::Output {
3736		b64(!self.0)
3737	}
3738}
3739impl core::ops::BitAnd for b64 {
3740	type Output = b64;
3741
3742	#[inline(always)]
3743	fn bitand(self, rhs: Self) -> Self::Output {
3744		b64(self.0 & rhs.0)
3745	}
3746}
3747impl core::ops::BitOr for b64 {
3748	type Output = b64;
3749
3750	#[inline(always)]
3751	fn bitor(self, rhs: Self) -> Self::Output {
3752		b64(self.0 | rhs.0)
3753	}
3754}
3755impl core::ops::BitXor for b64 {
3756	type Output = b64;
3757
3758	#[inline(always)]
3759	fn bitxor(self, rhs: Self) -> Self::Output {
3760		b64(self.0 ^ rhs.0)
3761	}
3762}
3763
3764impl Debug for b8 {
3765	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3766		#[allow(dead_code)]
3767		#[derive(Copy, Clone, Debug)]
3768		struct b8(bool, bool, bool, bool, bool, bool, bool, bool);
3769		b8(
3770			((self.0 >> 0) & 1) == 1,
3771			((self.0 >> 1) & 1) == 1,
3772			((self.0 >> 2) & 1) == 1,
3773			((self.0 >> 3) & 1) == 1,
3774			((self.0 >> 4) & 1) == 1,
3775			((self.0 >> 5) & 1) == 1,
3776			((self.0 >> 6) & 1) == 1,
3777			((self.0 >> 7) & 1) == 1,
3778		)
3779		.fmt(f)
3780	}
3781}
3782impl Debug for b16 {
3783	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3784		#[allow(dead_code)]
3785		#[derive(Copy, Clone, Debug)]
3786		struct b16(
3787			bool,
3788			bool,
3789			bool,
3790			bool,
3791			bool,
3792			bool,
3793			bool,
3794			bool,
3795			bool,
3796			bool,
3797			bool,
3798			bool,
3799			bool,
3800			bool,
3801			bool,
3802			bool,
3803		);
3804		b16(
3805			((self.0 >> 00) & 1) == 1,
3806			((self.0 >> 01) & 1) == 1,
3807			((self.0 >> 02) & 1) == 1,
3808			((self.0 >> 03) & 1) == 1,
3809			((self.0 >> 04) & 1) == 1,
3810			((self.0 >> 05) & 1) == 1,
3811			((self.0 >> 06) & 1) == 1,
3812			((self.0 >> 07) & 1) == 1,
3813			((self.0 >> 08) & 1) == 1,
3814			((self.0 >> 09) & 1) == 1,
3815			((self.0 >> 10) & 1) == 1,
3816			((self.0 >> 11) & 1) == 1,
3817			((self.0 >> 12) & 1) == 1,
3818			((self.0 >> 13) & 1) == 1,
3819			((self.0 >> 14) & 1) == 1,
3820			((self.0 >> 15) & 1) == 1,
3821		)
3822		.fmt(f)
3823	}
3824}
3825impl Debug for b32 {
3826	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3827		#[allow(dead_code)]
3828		#[derive(Copy, Clone, Debug)]
3829		struct b32(
3830			bool,
3831			bool,
3832			bool,
3833			bool,
3834			bool,
3835			bool,
3836			bool,
3837			bool,
3838			bool,
3839			bool,
3840			bool,
3841			bool,
3842			bool,
3843			bool,
3844			bool,
3845			bool,
3846			bool,
3847			bool,
3848			bool,
3849			bool,
3850			bool,
3851			bool,
3852			bool,
3853			bool,
3854			bool,
3855			bool,
3856			bool,
3857			bool,
3858			bool,
3859			bool,
3860			bool,
3861			bool,
3862		);
3863		b32(
3864			((self.0 >> 00) & 1) == 1,
3865			((self.0 >> 01) & 1) == 1,
3866			((self.0 >> 02) & 1) == 1,
3867			((self.0 >> 03) & 1) == 1,
3868			((self.0 >> 04) & 1) == 1,
3869			((self.0 >> 05) & 1) == 1,
3870			((self.0 >> 06) & 1) == 1,
3871			((self.0 >> 07) & 1) == 1,
3872			((self.0 >> 08) & 1) == 1,
3873			((self.0 >> 09) & 1) == 1,
3874			((self.0 >> 10) & 1) == 1,
3875			((self.0 >> 11) & 1) == 1,
3876			((self.0 >> 12) & 1) == 1,
3877			((self.0 >> 13) & 1) == 1,
3878			((self.0 >> 14) & 1) == 1,
3879			((self.0 >> 15) & 1) == 1,
3880			((self.0 >> 16) & 1) == 1,
3881			((self.0 >> 17) & 1) == 1,
3882			((self.0 >> 18) & 1) == 1,
3883			((self.0 >> 19) & 1) == 1,
3884			((self.0 >> 20) & 1) == 1,
3885			((self.0 >> 21) & 1) == 1,
3886			((self.0 >> 22) & 1) == 1,
3887			((self.0 >> 23) & 1) == 1,
3888			((self.0 >> 24) & 1) == 1,
3889			((self.0 >> 25) & 1) == 1,
3890			((self.0 >> 26) & 1) == 1,
3891			((self.0 >> 27) & 1) == 1,
3892			((self.0 >> 28) & 1) == 1,
3893			((self.0 >> 29) & 1) == 1,
3894			((self.0 >> 30) & 1) == 1,
3895			((self.0 >> 31) & 1) == 1,
3896		)
3897		.fmt(f)
3898	}
3899}
3900impl Debug for b64 {
3901	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
3902		#[allow(dead_code)]
3903		#[derive(Copy, Clone, Debug)]
3904		struct b64(
3905			bool,
3906			bool,
3907			bool,
3908			bool,
3909			bool,
3910			bool,
3911			bool,
3912			bool,
3913			bool,
3914			bool,
3915			bool,
3916			bool,
3917			bool,
3918			bool,
3919			bool,
3920			bool,
3921			bool,
3922			bool,
3923			bool,
3924			bool,
3925			bool,
3926			bool,
3927			bool,
3928			bool,
3929			bool,
3930			bool,
3931			bool,
3932			bool,
3933			bool,
3934			bool,
3935			bool,
3936			bool,
3937			bool,
3938			bool,
3939			bool,
3940			bool,
3941			bool,
3942			bool,
3943			bool,
3944			bool,
3945			bool,
3946			bool,
3947			bool,
3948			bool,
3949			bool,
3950			bool,
3951			bool,
3952			bool,
3953			bool,
3954			bool,
3955			bool,
3956			bool,
3957			bool,
3958			bool,
3959			bool,
3960			bool,
3961			bool,
3962			bool,
3963			bool,
3964			bool,
3965			bool,
3966			bool,
3967			bool,
3968			bool,
3969		);
3970		b64(
3971			((self.0 >> 00) & 1) == 1,
3972			((self.0 >> 01) & 1) == 1,
3973			((self.0 >> 02) & 1) == 1,
3974			((self.0 >> 03) & 1) == 1,
3975			((self.0 >> 04) & 1) == 1,
3976			((self.0 >> 05) & 1) == 1,
3977			((self.0 >> 06) & 1) == 1,
3978			((self.0 >> 07) & 1) == 1,
3979			((self.0 >> 08) & 1) == 1,
3980			((self.0 >> 09) & 1) == 1,
3981			((self.0 >> 10) & 1) == 1,
3982			((self.0 >> 11) & 1) == 1,
3983			((self.0 >> 12) & 1) == 1,
3984			((self.0 >> 13) & 1) == 1,
3985			((self.0 >> 14) & 1) == 1,
3986			((self.0 >> 15) & 1) == 1,
3987			((self.0 >> 16) & 1) == 1,
3988			((self.0 >> 17) & 1) == 1,
3989			((self.0 >> 18) & 1) == 1,
3990			((self.0 >> 19) & 1) == 1,
3991			((self.0 >> 20) & 1) == 1,
3992			((self.0 >> 21) & 1) == 1,
3993			((self.0 >> 22) & 1) == 1,
3994			((self.0 >> 23) & 1) == 1,
3995			((self.0 >> 24) & 1) == 1,
3996			((self.0 >> 25) & 1) == 1,
3997			((self.0 >> 26) & 1) == 1,
3998			((self.0 >> 27) & 1) == 1,
3999			((self.0 >> 28) & 1) == 1,
4000			((self.0 >> 29) & 1) == 1,
4001			((self.0 >> 30) & 1) == 1,
4002			((self.0 >> 31) & 1) == 1,
4003			((self.0 >> 32) & 1) == 1,
4004			((self.0 >> 33) & 1) == 1,
4005			((self.0 >> 34) & 1) == 1,
4006			((self.0 >> 35) & 1) == 1,
4007			((self.0 >> 36) & 1) == 1,
4008			((self.0 >> 37) & 1) == 1,
4009			((self.0 >> 38) & 1) == 1,
4010			((self.0 >> 39) & 1) == 1,
4011			((self.0 >> 40) & 1) == 1,
4012			((self.0 >> 41) & 1) == 1,
4013			((self.0 >> 42) & 1) == 1,
4014			((self.0 >> 43) & 1) == 1,
4015			((self.0 >> 44) & 1) == 1,
4016			((self.0 >> 45) & 1) == 1,
4017			((self.0 >> 46) & 1) == 1,
4018			((self.0 >> 47) & 1) == 1,
4019			((self.0 >> 48) & 1) == 1,
4020			((self.0 >> 49) & 1) == 1,
4021			((self.0 >> 50) & 1) == 1,
4022			((self.0 >> 51) & 1) == 1,
4023			((self.0 >> 52) & 1) == 1,
4024			((self.0 >> 53) & 1) == 1,
4025			((self.0 >> 54) & 1) == 1,
4026			((self.0 >> 55) & 1) == 1,
4027			((self.0 >> 56) & 1) == 1,
4028			((self.0 >> 57) & 1) == 1,
4029			((self.0 >> 58) & 1) == 1,
4030			((self.0 >> 59) & 1) == 1,
4031			((self.0 >> 60) & 1) == 1,
4032			((self.0 >> 61) & 1) == 1,
4033			((self.0 >> 62) & 1) == 1,
4034			((self.0 >> 63) & 1) == 1,
4035		)
4036		.fmt(f)
4037	}
4038}
4039
4040impl Debug for m8 {
4041	#[inline]
4042	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4043		self.is_set().fmt(f)
4044	}
4045}
4046impl Debug for m16 {
4047	#[inline]
4048	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4049		self.is_set().fmt(f)
4050	}
4051}
4052impl Debug for m32 {
4053	#[inline]
4054	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4055		self.is_set().fmt(f)
4056	}
4057}
4058impl Debug for m64 {
4059	#[inline]
4060	fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
4061		self.is_set().fmt(f)
4062	}
4063}
4064
4065impl m8 {
4066	/// Returns a mask with all bits set one, if `flag` is true, otherwise returns a mask with all
4067	/// bits set to zero.
4068	#[inline(always)]
4069	pub const fn new(flag: bool) -> Self {
4070		Self(if flag { u8::MAX } else { 0 })
4071	}
4072
4073	/// Returns `false` if the mask bits are all zero, otherwise returns `true`.
4074	#[inline(always)]
4075	pub const fn is_set(self) -> bool {
4076		self.0 != 0
4077	}
4078}
4079impl m16 {
4080	/// Returns a mask with all bits set one, if `flag` is true, otherwise returns a mask with all
4081	/// bits set to zero.
4082	#[inline(always)]
4083	pub const fn new(flag: bool) -> Self {
4084		Self(if flag { u16::MAX } else { 0 })
4085	}
4086
4087	/// Returns `false` if the mask bits are all zero, otherwise returns `true`.
4088	#[inline(always)]
4089	pub const fn is_set(self) -> bool {
4090		self.0 != 0
4091	}
4092}
4093impl m32 {
4094	/// Returns a mask with all bits set one, if `flag` is true, otherwise returns a mask with all
4095	/// bits set to zero.
4096	#[inline(always)]
4097	pub const fn new(flag: bool) -> Self {
4098		Self(if flag { u32::MAX } else { 0 })
4099	}
4100
4101	/// Returns `false` if the mask bits are all zero, otherwise returns `true`.
4102	#[inline(always)]
4103	pub const fn is_set(self) -> bool {
4104		self.0 != 0
4105	}
4106}
4107impl m64 {
4108	/// Returns a mask with all bits set one, if `flag` is true, otherwise returns a mask with all
4109	/// bits set to zero.
4110	#[inline(always)]
4111	pub const fn new(flag: bool) -> Self {
4112		Self(if flag { u64::MAX } else { 0 })
4113	}
4114
4115	/// Returns `false` if the mask bits are all zero, otherwise returns `true`.
4116	#[inline(always)]
4117	pub const fn is_set(self) -> bool {
4118		self.0 != 0
4119	}
4120}
4121
4122/// A 128-bit SIMD vector with 16 elements of type [`i8`].
4123#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4124#[repr(C)]
4125pub struct i8x16(
4126	pub i8,
4127	pub i8,
4128	pub i8,
4129	pub i8,
4130	pub i8,
4131	pub i8,
4132	pub i8,
4133	pub i8,
4134	pub i8,
4135	pub i8,
4136	pub i8,
4137	pub i8,
4138	pub i8,
4139	pub i8,
4140	pub i8,
4141	pub i8,
4142);
4143/// A 256-bit SIMD vector with 32 elements of type [`i8`].
4144#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4145#[repr(C)]
4146pub struct i8x32(
4147	pub i8,
4148	pub i8,
4149	pub i8,
4150	pub i8,
4151	pub i8,
4152	pub i8,
4153	pub i8,
4154	pub i8,
4155	pub i8,
4156	pub i8,
4157	pub i8,
4158	pub i8,
4159	pub i8,
4160	pub i8,
4161	pub i8,
4162	pub i8,
4163	pub i8,
4164	pub i8,
4165	pub i8,
4166	pub i8,
4167	pub i8,
4168	pub i8,
4169	pub i8,
4170	pub i8,
4171	pub i8,
4172	pub i8,
4173	pub i8,
4174	pub i8,
4175	pub i8,
4176	pub i8,
4177	pub i8,
4178	pub i8,
4179);
4180/// A 512-bit SIMD vector with 64 elements of type [`i8`].
4181#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4182#[repr(C)]
4183pub struct i8x64(
4184	pub i8,
4185	pub i8,
4186	pub i8,
4187	pub i8,
4188	pub i8,
4189	pub i8,
4190	pub i8,
4191	pub i8,
4192	pub i8,
4193	pub i8,
4194	pub i8,
4195	pub i8,
4196	pub i8,
4197	pub i8,
4198	pub i8,
4199	pub i8,
4200	pub i8,
4201	pub i8,
4202	pub i8,
4203	pub i8,
4204	pub i8,
4205	pub i8,
4206	pub i8,
4207	pub i8,
4208	pub i8,
4209	pub i8,
4210	pub i8,
4211	pub i8,
4212	pub i8,
4213	pub i8,
4214	pub i8,
4215	pub i8,
4216	pub i8,
4217	pub i8,
4218	pub i8,
4219	pub i8,
4220	pub i8,
4221	pub i8,
4222	pub i8,
4223	pub i8,
4224	pub i8,
4225	pub i8,
4226	pub i8,
4227	pub i8,
4228	pub i8,
4229	pub i8,
4230	pub i8,
4231	pub i8,
4232	pub i8,
4233	pub i8,
4234	pub i8,
4235	pub i8,
4236	pub i8,
4237	pub i8,
4238	pub i8,
4239	pub i8,
4240	pub i8,
4241	pub i8,
4242	pub i8,
4243	pub i8,
4244	pub i8,
4245	pub i8,
4246	pub i8,
4247	pub i8,
4248);
4249
4250/// A 128-bit SIMD vector with 16 elements of type [`u8`].
4251#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4252#[repr(C)]
4253pub struct u8x16(
4254	pub u8,
4255	pub u8,
4256	pub u8,
4257	pub u8,
4258	pub u8,
4259	pub u8,
4260	pub u8,
4261	pub u8,
4262	pub u8,
4263	pub u8,
4264	pub u8,
4265	pub u8,
4266	pub u8,
4267	pub u8,
4268	pub u8,
4269	pub u8,
4270);
4271/// A 256-bit SIMD vector with 32 elements of type [`u8`].
4272#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4273#[repr(C)]
4274pub struct u8x32(
4275	pub u8,
4276	pub u8,
4277	pub u8,
4278	pub u8,
4279	pub u8,
4280	pub u8,
4281	pub u8,
4282	pub u8,
4283	pub u8,
4284	pub u8,
4285	pub u8,
4286	pub u8,
4287	pub u8,
4288	pub u8,
4289	pub u8,
4290	pub u8,
4291	pub u8,
4292	pub u8,
4293	pub u8,
4294	pub u8,
4295	pub u8,
4296	pub u8,
4297	pub u8,
4298	pub u8,
4299	pub u8,
4300	pub u8,
4301	pub u8,
4302	pub u8,
4303	pub u8,
4304	pub u8,
4305	pub u8,
4306	pub u8,
4307);
4308/// A 512-bit SIMD vector with 64 elements of type [`u8`].
4309#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4310#[repr(C)]
4311pub struct u8x64(
4312	pub u8,
4313	pub u8,
4314	pub u8,
4315	pub u8,
4316	pub u8,
4317	pub u8,
4318	pub u8,
4319	pub u8,
4320	pub u8,
4321	pub u8,
4322	pub u8,
4323	pub u8,
4324	pub u8,
4325	pub u8,
4326	pub u8,
4327	pub u8,
4328	pub u8,
4329	pub u8,
4330	pub u8,
4331	pub u8,
4332	pub u8,
4333	pub u8,
4334	pub u8,
4335	pub u8,
4336	pub u8,
4337	pub u8,
4338	pub u8,
4339	pub u8,
4340	pub u8,
4341	pub u8,
4342	pub u8,
4343	pub u8,
4344	pub u8,
4345	pub u8,
4346	pub u8,
4347	pub u8,
4348	pub u8,
4349	pub u8,
4350	pub u8,
4351	pub u8,
4352	pub u8,
4353	pub u8,
4354	pub u8,
4355	pub u8,
4356	pub u8,
4357	pub u8,
4358	pub u8,
4359	pub u8,
4360	pub u8,
4361	pub u8,
4362	pub u8,
4363	pub u8,
4364	pub u8,
4365	pub u8,
4366	pub u8,
4367	pub u8,
4368	pub u8,
4369	pub u8,
4370	pub u8,
4371	pub u8,
4372	pub u8,
4373	pub u8,
4374	pub u8,
4375	pub u8,
4376);
4377
4378/// A 128-bit SIMD vector with 16 elements of type [`m8`].
4379#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4380#[repr(C)]
4381pub struct m8x16(
4382	pub m8,
4383	pub m8,
4384	pub m8,
4385	pub m8,
4386	pub m8,
4387	pub m8,
4388	pub m8,
4389	pub m8,
4390	pub m8,
4391	pub m8,
4392	pub m8,
4393	pub m8,
4394	pub m8,
4395	pub m8,
4396	pub m8,
4397	pub m8,
4398);
4399/// A 256-bit SIMD vector with 32 elements of type [`m8`].
4400#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4401#[repr(C)]
4402pub struct m8x32(
4403	pub m8,
4404	pub m8,
4405	pub m8,
4406	pub m8,
4407	pub m8,
4408	pub m8,
4409	pub m8,
4410	pub m8,
4411	pub m8,
4412	pub m8,
4413	pub m8,
4414	pub m8,
4415	pub m8,
4416	pub m8,
4417	pub m8,
4418	pub m8,
4419	pub m8,
4420	pub m8,
4421	pub m8,
4422	pub m8,
4423	pub m8,
4424	pub m8,
4425	pub m8,
4426	pub m8,
4427	pub m8,
4428	pub m8,
4429	pub m8,
4430	pub m8,
4431	pub m8,
4432	pub m8,
4433	pub m8,
4434	pub m8,
4435);
4436
4437/// A 512-bit SIMD vector with 64 elements of type [`m8`].
4438#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4439#[repr(C)]
4440pub struct m8x64(
4441	pub m8,
4442	pub m8,
4443	pub m8,
4444	pub m8,
4445	pub m8,
4446	pub m8,
4447	pub m8,
4448	pub m8,
4449	pub m8,
4450	pub m8,
4451	pub m8,
4452	pub m8,
4453	pub m8,
4454	pub m8,
4455	pub m8,
4456	pub m8,
4457	pub m8,
4458	pub m8,
4459	pub m8,
4460	pub m8,
4461	pub m8,
4462	pub m8,
4463	pub m8,
4464	pub m8,
4465	pub m8,
4466	pub m8,
4467	pub m8,
4468	pub m8,
4469	pub m8,
4470	pub m8,
4471	pub m8,
4472	pub m8,
4473	pub m8,
4474	pub m8,
4475	pub m8,
4476	pub m8,
4477	pub m8,
4478	pub m8,
4479	pub m8,
4480	pub m8,
4481	pub m8,
4482	pub m8,
4483	pub m8,
4484	pub m8,
4485	pub m8,
4486	pub m8,
4487	pub m8,
4488	pub m8,
4489	pub m8,
4490	pub m8,
4491	pub m8,
4492	pub m8,
4493	pub m8,
4494	pub m8,
4495	pub m8,
4496	pub m8,
4497	pub m8,
4498	pub m8,
4499	pub m8,
4500	pub m8,
4501	pub m8,
4502	pub m8,
4503	pub m8,
4504	pub m8,
4505);
4506
4507/// A 128-bit SIMD vector with 8 elements of type [`i16`].
4508#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4509#[repr(C)]
4510pub struct i16x8(
4511	pub i16,
4512	pub i16,
4513	pub i16,
4514	pub i16,
4515	pub i16,
4516	pub i16,
4517	pub i16,
4518	pub i16,
4519);
4520/// A 256-bit SIMD vector with 16 elements of type [`i16`].
4521#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4522#[repr(C)]
4523pub struct i16x16(
4524	pub i16,
4525	pub i16,
4526	pub i16,
4527	pub i16,
4528	pub i16,
4529	pub i16,
4530	pub i16,
4531	pub i16,
4532	pub i16,
4533	pub i16,
4534	pub i16,
4535	pub i16,
4536	pub i16,
4537	pub i16,
4538	pub i16,
4539	pub i16,
4540);
4541/// A 512-bit SIMD vector with 32 elements of type [`i16`].
4542#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4543#[repr(C)]
4544pub struct i16x32(
4545	pub i16,
4546	pub i16,
4547	pub i16,
4548	pub i16,
4549	pub i16,
4550	pub i16,
4551	pub i16,
4552	pub i16,
4553	pub i16,
4554	pub i16,
4555	pub i16,
4556	pub i16,
4557	pub i16,
4558	pub i16,
4559	pub i16,
4560	pub i16,
4561	pub i16,
4562	pub i16,
4563	pub i16,
4564	pub i16,
4565	pub i16,
4566	pub i16,
4567	pub i16,
4568	pub i16,
4569	pub i16,
4570	pub i16,
4571	pub i16,
4572	pub i16,
4573	pub i16,
4574	pub i16,
4575	pub i16,
4576	pub i16,
4577);
4578
4579/// A 128-bit SIMD vector with 8 elements of type [`u16`].
4580#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4581#[repr(C)]
4582pub struct u16x8(
4583	pub u16,
4584	pub u16,
4585	pub u16,
4586	pub u16,
4587	pub u16,
4588	pub u16,
4589	pub u16,
4590	pub u16,
4591);
4592/// A 256-bit SIMD vector with 16 elements of type [`u16`].
4593#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4594#[repr(C)]
4595pub struct u16x16(
4596	pub u16,
4597	pub u16,
4598	pub u16,
4599	pub u16,
4600	pub u16,
4601	pub u16,
4602	pub u16,
4603	pub u16,
4604	pub u16,
4605	pub u16,
4606	pub u16,
4607	pub u16,
4608	pub u16,
4609	pub u16,
4610	pub u16,
4611	pub u16,
4612);
4613/// A 512-bit SIMD vector with 32 elements of type [`u16`].
4614#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4615#[repr(C)]
4616pub struct u16x32(
4617	pub u16,
4618	pub u16,
4619	pub u16,
4620	pub u16,
4621	pub u16,
4622	pub u16,
4623	pub u16,
4624	pub u16,
4625	pub u16,
4626	pub u16,
4627	pub u16,
4628	pub u16,
4629	pub u16,
4630	pub u16,
4631	pub u16,
4632	pub u16,
4633	pub u16,
4634	pub u16,
4635	pub u16,
4636	pub u16,
4637	pub u16,
4638	pub u16,
4639	pub u16,
4640	pub u16,
4641	pub u16,
4642	pub u16,
4643	pub u16,
4644	pub u16,
4645	pub u16,
4646	pub u16,
4647	pub u16,
4648	pub u16,
4649);
4650
4651/// A 128-bit SIMD vector with 8 elements of type [`m16`].
4652#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4653#[repr(C)]
4654pub struct m16x8(
4655	pub m16,
4656	pub m16,
4657	pub m16,
4658	pub m16,
4659	pub m16,
4660	pub m16,
4661	pub m16,
4662	pub m16,
4663);
4664/// A 256-bit SIMD vector with 16 elements of type [`m16`].
4665#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4666#[repr(C)]
4667pub struct m16x16(
4668	pub m16,
4669	pub m16,
4670	pub m16,
4671	pub m16,
4672	pub m16,
4673	pub m16,
4674	pub m16,
4675	pub m16,
4676	pub m16,
4677	pub m16,
4678	pub m16,
4679	pub m16,
4680	pub m16,
4681	pub m16,
4682	pub m16,
4683	pub m16,
4684);
4685/// A 512-bit SIMD vector with 32 elements of type [`m16`].
4686#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4687#[repr(C)]
4688pub struct m16x32(
4689	pub m16,
4690	pub m16,
4691	pub m16,
4692	pub m16,
4693	pub m16,
4694	pub m16,
4695	pub m16,
4696	pub m16,
4697	pub m16,
4698	pub m16,
4699	pub m16,
4700	pub m16,
4701	pub m16,
4702	pub m16,
4703	pub m16,
4704	pub m16,
4705	pub m16,
4706	pub m16,
4707	pub m16,
4708	pub m16,
4709	pub m16,
4710	pub m16,
4711	pub m16,
4712	pub m16,
4713	pub m16,
4714	pub m16,
4715	pub m16,
4716	pub m16,
4717	pub m16,
4718	pub m16,
4719	pub m16,
4720	pub m16,
4721);
4722
4723/// A 128-bit SIMD vector with 4 elements of type [`f32`].
4724#[derive(Debug, Copy, Clone, PartialEq)]
4725#[repr(C)]
4726pub struct f32x4(pub f32, pub f32, pub f32, pub f32);
4727
4728/// A 256-bit SIMD vector with 8 elements of type [`f32`].
4729#[derive(Debug, Copy, Clone, PartialEq)]
4730#[repr(C)]
4731pub struct f32x8(
4732	pub f32,
4733	pub f32,
4734	pub f32,
4735	pub f32,
4736	pub f32,
4737	pub f32,
4738	pub f32,
4739	pub f32,
4740);
4741/// A 512-bit SIMD vector with 16 elements of type [`f32`].
4742#[derive(Debug, Copy, Clone, PartialEq)]
4743#[repr(C)]
4744pub struct f32x16(
4745	pub f32,
4746	pub f32,
4747	pub f32,
4748	pub f32,
4749	pub f32,
4750	pub f32,
4751	pub f32,
4752	pub f32,
4753	pub f32,
4754	pub f32,
4755	pub f32,
4756	pub f32,
4757	pub f32,
4758	pub f32,
4759	pub f32,
4760	pub f32,
4761);
4762
4763/// A 128-bit SIMD vector with 2 elements of type [`c32`].
4764#[derive(Copy, Clone, PartialEq)]
4765#[repr(C)]
4766pub struct c32x2(pub c32, pub c32);
4767
4768impl Debug for c32x2 {
4769	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4770		#[derive(Copy, Clone, Debug)]
4771		#[repr(C)]
4772		pub struct c32x2(pub DebugCplx<c32>, pub DebugCplx<c32>);
4773		unsafe impl Zeroable for c32x2 {}
4774		unsafe impl Pod for c32x2 {}
4775
4776		let this: c32x2 = cast!(*self);
4777		this.fmt(f)
4778	}
4779}
4780
4781/// A 256-bit SIMD vector with 4 elements of type [`c32`].
4782#[derive(Copy, Clone, PartialEq)]
4783#[repr(C)]
4784pub struct c32x4(pub c32, pub c32, pub c32, pub c32);
4785
4786impl Debug for c32x4 {
4787	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4788		#[derive(Copy, Clone, Debug)]
4789		#[repr(C)]
4790		pub struct c32x4(
4791			pub DebugCplx<c32>,
4792			pub DebugCplx<c32>,
4793			pub DebugCplx<c32>,
4794			pub DebugCplx<c32>,
4795		);
4796		unsafe impl Zeroable for c32x4 {}
4797		unsafe impl Pod for c32x4 {}
4798
4799		let this: c32x4 = cast!(*self);
4800		this.fmt(f)
4801	}
4802}
4803
4804/// A 512-bit SIMD vector with 8 elements of type [`c32`].
4805#[derive(Copy, Clone, PartialEq)]
4806#[repr(C)]
4807pub struct c32x8(
4808	pub c32,
4809	pub c32,
4810	pub c32,
4811	pub c32,
4812	pub c32,
4813	pub c32,
4814	pub c32,
4815	pub c32,
4816);
4817
4818impl Debug for c32x8 {
4819	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4820		#[derive(Copy, Clone, Debug)]
4821		#[repr(C)]
4822		pub struct c32x8(
4823			pub DebugCplx<c32>,
4824			pub DebugCplx<c32>,
4825			pub DebugCplx<c32>,
4826			pub DebugCplx<c32>,
4827			pub DebugCplx<c32>,
4828			pub DebugCplx<c32>,
4829			pub DebugCplx<c32>,
4830			pub DebugCplx<c32>,
4831		);
4832		unsafe impl Zeroable for c32x8 {}
4833		unsafe impl Pod for c32x8 {}
4834
4835		let this: c32x8 = cast!(*self);
4836		this.fmt(f)
4837	}
4838}
4839/// A 128-bit SIMD vector with 4 elements of type [`i32`].
4840#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4841#[repr(C)]
4842pub struct i32x4(pub i32, pub i32, pub i32, pub i32);
4843/// A 256-bit SIMD vector with 8 elements of type [`i32`].
4844#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4845#[repr(C)]
4846pub struct i32x8(
4847	pub i32,
4848	pub i32,
4849	pub i32,
4850	pub i32,
4851	pub i32,
4852	pub i32,
4853	pub i32,
4854	pub i32,
4855);
4856/// A 512-bit SIMD vector with 16 elements of type [`i32`].
4857#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4858#[repr(C)]
4859pub struct i32x16(
4860	pub i32,
4861	pub i32,
4862	pub i32,
4863	pub i32,
4864	pub i32,
4865	pub i32,
4866	pub i32,
4867	pub i32,
4868	pub i32,
4869	pub i32,
4870	pub i32,
4871	pub i32,
4872	pub i32,
4873	pub i32,
4874	pub i32,
4875	pub i32,
4876);
4877
4878/// A 128-bit SIMD vector with 4 elements of type [`u32`].
4879#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4880#[repr(C)]
4881pub struct u32x4(pub u32, pub u32, pub u32, pub u32);
4882/// A 256-bit SIMD vector with 8 elements of type [`u32`].
4883#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4884#[repr(C)]
4885pub struct u32x8(
4886	pub u32,
4887	pub u32,
4888	pub u32,
4889	pub u32,
4890	pub u32,
4891	pub u32,
4892	pub u32,
4893	pub u32,
4894);
4895/// A 512-bit SIMD vector with 16 elements of type [`u32`].
4896#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4897#[repr(C)]
4898pub struct u32x16(
4899	pub u32,
4900	pub u32,
4901	pub u32,
4902	pub u32,
4903	pub u32,
4904	pub u32,
4905	pub u32,
4906	pub u32,
4907	pub u32,
4908	pub u32,
4909	pub u32,
4910	pub u32,
4911	pub u32,
4912	pub u32,
4913	pub u32,
4914	pub u32,
4915);
4916
4917/// A 128-bit SIMD vector with 4 elements of type [`m32`].
4918#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4919#[repr(C)]
4920pub struct m32x4(pub m32, pub m32, pub m32, pub m32);
4921/// A 256-bit SIMD vector with 8 elements of type [`m32`].
4922#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4923#[repr(C)]
4924pub struct m32x8(
4925	pub m32,
4926	pub m32,
4927	pub m32,
4928	pub m32,
4929	pub m32,
4930	pub m32,
4931	pub m32,
4932	pub m32,
4933);
4934/// A 512-bit SIMD vector with 16 elements of type [`m32`].
4935#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4936#[repr(C)]
4937pub struct m32x16(
4938	pub m32,
4939	pub m32,
4940	pub m32,
4941	pub m32,
4942	pub m32,
4943	pub m32,
4944	pub m32,
4945	pub m32,
4946	pub m32,
4947	pub m32,
4948	pub m32,
4949	pub m32,
4950	pub m32,
4951	pub m32,
4952	pub m32,
4953	pub m32,
4954);
4955
4956/// A 128-bit SIMD vector with 2 elements of type [`f64`].
4957#[derive(Debug, Copy, Clone, PartialEq)]
4958#[repr(C)]
4959pub struct f64x2(pub f64, pub f64);
4960/// A 256-bit SIMD vector with 4 elements of type [`f64`].
4961#[derive(Debug, Copy, Clone, PartialEq)]
4962#[repr(C)]
4963pub struct f64x4(pub f64, pub f64, pub f64, pub f64);
4964/// A 512-bit SIMD vector with 8 elements of type [`f64`].
4965#[derive(Debug, Copy, Clone, PartialEq)]
4966#[repr(C)]
4967pub struct f64x8(
4968	pub f64,
4969	pub f64,
4970	pub f64,
4971	pub f64,
4972	pub f64,
4973	pub f64,
4974	pub f64,
4975	pub f64,
4976);
4977
4978/// A 128-bit SIMD vector with 1 elements of type [`c64`].
4979#[derive(Copy, Clone, PartialEq)]
4980#[repr(C)]
4981pub struct c64x1(pub c64);
4982
4983impl Debug for c64x1 {
4984	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4985		#[derive(Copy, Clone, Debug)]
4986		#[repr(C)]
4987		pub struct c64x1(pub DebugCplx<c64>);
4988		unsafe impl Zeroable for c64x1 {}
4989		unsafe impl Pod for c64x1 {}
4990
4991		let this: c64x1 = cast!(*self);
4992		this.fmt(f)
4993	}
4994}
4995
4996/// A 256-bit SIMD vector with 2 elements of type [`c64`].
4997#[derive(Copy, Clone, PartialEq)]
4998#[repr(C)]
4999pub struct c64x2(pub c64, pub c64);
5000
5001impl Debug for c64x2 {
5002	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5003		#[derive(Copy, Clone, Debug)]
5004		#[repr(C)]
5005		pub struct c64x2(pub DebugCplx<c64>, pub DebugCplx<c64>);
5006		unsafe impl Zeroable for c64x2 {}
5007		unsafe impl Pod for c64x2 {}
5008
5009		let this: c64x2 = cast!(*self);
5010		this.fmt(f)
5011	}
5012}
5013
5014/// A 512-bit SIMD vector with 4 elements of type [`c64`].
5015#[derive(Copy, Clone, PartialEq)]
5016#[repr(C)]
5017pub struct c64x4(pub c64, pub c64, pub c64, pub c64);
5018
5019impl Debug for c64x4 {
5020	fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5021		#[derive(Copy, Clone, Debug)]
5022		#[repr(C)]
5023		pub struct c64x4(
5024			pub DebugCplx<c64>,
5025			pub DebugCplx<c64>,
5026			pub DebugCplx<c64>,
5027			pub DebugCplx<c64>,
5028		);
5029		unsafe impl Zeroable for c64x4 {}
5030		unsafe impl Pod for c64x4 {}
5031
5032		let this: c64x4 = cast!(*self);
5033		this.fmt(f)
5034	}
5035}
5036
5037/// A 128-bit SIMD vector with 2 elements of type [`i64`].
5038#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5039#[repr(C)]
5040pub struct i64x2(pub i64, pub i64);
5041/// A 256-bit SIMD vector with 4 elements of type [`i64`].
5042#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5043#[repr(C)]
5044pub struct i64x4(pub i64, pub i64, pub i64, pub i64);
5045/// A 512-bit SIMD vector with 8 elements of type [`i64`].
5046#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5047#[repr(C)]
5048pub struct i64x8(
5049	pub i64,
5050	pub i64,
5051	pub i64,
5052	pub i64,
5053	pub i64,
5054	pub i64,
5055	pub i64,
5056	pub i64,
5057);
5058
5059/// A 128-bit SIMD vector with 2 elements of type [`u64`].
5060#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5061#[repr(C)]
5062pub struct u64x2(pub u64, pub u64);
5063/// A 256-bit SIMD vector with 4 elements of type [`u64`].
5064#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5065#[repr(C)]
5066pub struct u64x4(pub u64, pub u64, pub u64, pub u64);
5067/// A 512-bit SIMD vector with 8 elements of type [`u64`].
5068#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5069#[repr(C)]
5070pub struct u64x8(
5071	pub u64,
5072	pub u64,
5073	pub u64,
5074	pub u64,
5075	pub u64,
5076	pub u64,
5077	pub u64,
5078	pub u64,
5079);
5080
5081/// A 128-bit SIMD vector with 2 elements of type [`m64`].
5082#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5083#[repr(C)]
5084pub struct m64x2(pub m64, pub m64);
5085/// A 256-bit SIMD vector with 4 elements of type [`m64`].
5086#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5087#[repr(C)]
5088pub struct m64x4(pub m64, pub m64, pub m64, pub m64);
5089/// A 512-bit SIMD vector with 8 elements of type [`m64`].
5090#[derive(Debug, Copy, Clone, PartialEq, Eq)]
5091#[repr(C)]
5092pub struct m64x8(
5093	pub m64,
5094	pub m64,
5095	pub m64,
5096	pub m64,
5097	pub m64,
5098	pub m64,
5099	pub m64,
5100	pub m64,
5101);
5102
5103unsafe impl Zeroable for m8 {}
5104unsafe impl Zeroable for m16 {}
5105unsafe impl Zeroable for m32 {}
5106unsafe impl Zeroable for m64 {}
5107unsafe impl Pod for m8 {}
5108unsafe impl Pod for m16 {}
5109unsafe impl Pod for m32 {}
5110unsafe impl Pod for m64 {}
5111
5112unsafe impl Zeroable for b8 {}
5113unsafe impl Pod for b8 {}
5114unsafe impl Zeroable for b16 {}
5115unsafe impl Pod for b16 {}
5116unsafe impl Zeroable for b32 {}
5117unsafe impl Pod for b32 {}
5118unsafe impl Zeroable for b64 {}
5119unsafe impl Pod for b64 {}
5120
5121unsafe impl Zeroable for i8x16 {}
5122unsafe impl Zeroable for i8x32 {}
5123unsafe impl Zeroable for i8x64 {}
5124unsafe impl Pod for i8x16 {}
5125unsafe impl Pod for i8x32 {}
5126unsafe impl Pod for i8x64 {}
5127unsafe impl Zeroable for u8x16 {}
5128unsafe impl Zeroable for u8x32 {}
5129unsafe impl Zeroable for u8x64 {}
5130unsafe impl Pod for u8x16 {}
5131unsafe impl Pod for u8x32 {}
5132unsafe impl Pod for u8x64 {}
5133unsafe impl Zeroable for m8x16 {}
5134unsafe impl Zeroable for m8x32 {}
5135unsafe impl Zeroable for m8x64 {}
5136unsafe impl Pod for m8x16 {}
5137unsafe impl Pod for m8x32 {}
5138unsafe impl Pod for m8x64 {}
5139
5140unsafe impl Zeroable for i16x8 {}
5141unsafe impl Zeroable for i16x16 {}
5142unsafe impl Zeroable for i16x32 {}
5143unsafe impl Pod for i16x8 {}
5144unsafe impl Pod for i16x16 {}
5145unsafe impl Pod for i16x32 {}
5146unsafe impl Zeroable for u16x8 {}
5147unsafe impl Zeroable for u16x16 {}
5148unsafe impl Zeroable for u16x32 {}
5149unsafe impl Pod for u16x8 {}
5150unsafe impl Pod for u16x16 {}
5151unsafe impl Pod for u16x32 {}
5152unsafe impl Zeroable for m16x8 {}
5153unsafe impl Zeroable for m16x16 {}
5154unsafe impl Zeroable for m16x32 {}
5155unsafe impl Pod for m16x8 {}
5156unsafe impl Pod for m16x16 {}
5157unsafe impl Pod for m16x32 {}
5158
5159unsafe impl Zeroable for f32x4 {}
5160unsafe impl Zeroable for f32x8 {}
5161unsafe impl Zeroable for f32x16 {}
5162unsafe impl Pod for f32x4 {}
5163unsafe impl Pod for f32x8 {}
5164unsafe impl Pod for f32x16 {}
5165unsafe impl Zeroable for c32x2 {}
5166unsafe impl Zeroable for c32x4 {}
5167unsafe impl Zeroable for c32x8 {}
5168unsafe impl Pod for c32x2 {}
5169unsafe impl Pod for c32x4 {}
5170unsafe impl Pod for c32x8 {}
5171unsafe impl Zeroable for i32x4 {}
5172unsafe impl Zeroable for i32x8 {}
5173unsafe impl Zeroable for i32x16 {}
5174unsafe impl Pod for i32x4 {}
5175unsafe impl Pod for i32x8 {}
5176unsafe impl Pod for i32x16 {}
5177unsafe impl Zeroable for u32x4 {}
5178unsafe impl Zeroable for u32x8 {}
5179unsafe impl Zeroable for u32x16 {}
5180unsafe impl Pod for u32x4 {}
5181unsafe impl Pod for u32x8 {}
5182unsafe impl Pod for u32x16 {}
5183unsafe impl Zeroable for m32x4 {}
5184unsafe impl Zeroable for m32x8 {}
5185unsafe impl Zeroable for m32x16 {}
5186unsafe impl Pod for m32x4 {}
5187unsafe impl Pod for m32x8 {}
5188unsafe impl Pod for m32x16 {}
5189
5190unsafe impl Zeroable for f64x2 {}
5191unsafe impl Zeroable for f64x4 {}
5192unsafe impl Zeroable for f64x8 {}
5193unsafe impl Pod for f64x2 {}
5194unsafe impl Pod for f64x4 {}
5195unsafe impl Pod for f64x8 {}
5196unsafe impl Zeroable for c64x1 {}
5197unsafe impl Zeroable for c64x2 {}
5198unsafe impl Zeroable for c64x4 {}
5199unsafe impl Pod for c64x1 {}
5200unsafe impl Pod for c64x2 {}
5201unsafe impl Pod for c64x4 {}
5202unsafe impl Zeroable for i64x2 {}
5203unsafe impl Zeroable for i64x4 {}
5204unsafe impl Zeroable for i64x8 {}
5205unsafe impl Pod for i64x2 {}
5206unsafe impl Pod for i64x4 {}
5207unsafe impl Pod for i64x8 {}
5208unsafe impl Zeroable for u64x2 {}
5209unsafe impl Zeroable for u64x4 {}
5210unsafe impl Zeroable for u64x8 {}
5211unsafe impl Pod for u64x2 {}
5212unsafe impl Pod for u64x4 {}
5213unsafe impl Pod for u64x8 {}
5214unsafe impl Zeroable for m64x2 {}
5215unsafe impl Zeroable for m64x4 {}
5216unsafe impl Zeroable for m64x8 {}
5217unsafe impl Pod for m64x2 {}
5218unsafe impl Pod for m64x4 {}
5219unsafe impl Pod for m64x8 {}
5220
5221macro_rules! iota {
5222	($T: ty, $N: expr, $int: ty) => {
5223		const {
5224			unsafe {
5225				let mut iota = [const { core::mem::MaybeUninit::uninit() }; $N];
5226				{
5227					let mut i = 0;
5228					while i < $N {
5229						let v = (&raw mut iota[i]) as *mut $int;
5230
5231						let mut j = 0;
5232						while j < core::mem::size_of::<$T>() / core::mem::size_of::<$int>() {
5233							v.add(j).write_unaligned(i as $int);
5234							j += 1;
5235						}
5236
5237						i += 1;
5238					}
5239				}
5240				iota
5241			}
5242		}
5243	};
5244}
5245
5246pub const fn iota_8<T: Interleave, const N: usize>() -> [MaybeUninit<T>; N] {
5247	iota!(T, N, u8)
5248}
5249pub const fn iota_16<T: Interleave, const N: usize>() -> [MaybeUninit<T>; N] {
5250	iota!(T, N, u16)
5251}
5252pub const fn iota_32<T: Interleave, const N: usize>() -> [MaybeUninit<T>; N] {
5253	iota!(T, N, u32)
5254}
5255pub const fn iota_64<T: Interleave, const N: usize>() -> [MaybeUninit<T>; N] {
5256	iota!(T, N, u64)
5257}
5258
5259#[cfg(target_arch = "x86_64")]
5260#[cfg(test)]
5261mod tests {
5262	use super::*;
5263
5264	#[test]
5265	fn test_interleave() {
5266		if let Some(simd) = x86::V3::try_new() {
5267			{
5268				let src = [f64x4(0.0, 0.1, 1.0, 1.1), f64x4(2.0, 2.1, 3.0, 3.1)];
5269				let dst = unsafe { deinterleave_fallback::<f64, f64x4, [f64x4; 2]>(src) };
5270				assert_eq!(dst[1], simd.add_f64x4(dst[0], simd.splat_f64x4(0.1)));
5271				assert_eq!(src, unsafe {
5272					interleave_fallback::<f64, f64x4, [f64x4; 2]>(dst)
5273				});
5274			}
5275			{
5276				let src = [
5277					f64x4(0.0, 0.1, 0.2, 0.3),
5278					f64x4(1.0, 1.1, 1.2, 1.3),
5279					f64x4(2.0, 2.1, 2.2, 2.3),
5280					f64x4(3.0, 3.1, 3.2, 3.3),
5281				];
5282				let dst = unsafe { deinterleave_fallback::<f64, f64x4, [f64x4; 4]>(src) };
5283				assert_eq!(dst[1], simd.add_f64x4(dst[0], simd.splat_f64x4(0.1)));
5284				assert_eq!(dst[2], simd.add_f64x4(dst[0], simd.splat_f64x4(0.2)));
5285				assert_eq!(dst[3], simd.add_f64x4(dst[0], simd.splat_f64x4(0.3)));
5286				assert_eq!(src, unsafe {
5287					interleave_fallback::<f64, f64x4, [f64x4; 4]>(dst)
5288				});
5289			}
5290		}
5291	}
5292}