Skip to main content

wide/
lib.rs

1#![no_std]
2#![allow(non_camel_case_types)]
3#![warn(clippy::doc_markdown)]
4#![warn(clippy::missing_inline_in_public_items)]
5#![allow(clippy::eq_op)]
6#![allow(clippy::excessive_precision)]
7#![allow(clippy::let_and_return)]
8#![allow(clippy::unusual_byte_groupings)]
9#![allow(clippy::misrefactored_assign_op)]
10#![allow(clippy::approx_constant)]
11
12//! A crate to help you go wide.
13//!
14//! This crate provides SIMD-compatible data types.
15//!
16//! When possible, explicit SIMD is used with all the math operations here. As a
17//! fallback, the fact that all the lengths of a fixed length array are doing
18//! the same thing will often make LLVM notice that it should use SIMD
19//! instructions to complete the task. In the worst case, the code just becomes
20//! totally scalar (though the math is still correct, at least).
21//!
22//! ## Casting
23//!
24//! The SIMD types implement the [`bytemuck::Pod`] trait, which means that it
25//! is possible to do bitwise casts between SIMD types of the same size with
26//! the [`bytemuck::cast()`] function and others. `bytemuck` is re-exported by
27//! this crate for convenience.
28//!
29//! This typically does not have much, if any, runtime overhead in optimized
30//! builds.
31//!
32//! ## Crate Features
33//!
34//! * `std`: This causes the feature to link to `std`.
35//!   * Currently this just improves the performance of `sqrt` when an explicit
36//!     SIMD `sqrt` isn't available.
37
38// Note(Lokathor): Due to standard library magic, the std-only methods for f32
39// and f64 will automatically be available simply by declaring this.
40#[cfg(feature = "std")]
41extern crate std;
42
43// TODO
44// Add/Sub/Mul/Div with constant
45// Shuffle left/right/by index
46
47use core::{
48  fmt::{
49    Binary, Debug, Display, LowerExp, LowerHex, Octal, UpperExp, UpperHex,
50  },
51  ops::*,
52};
53
54#[allow(unused_imports)]
55#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
56use safe_arch::*;
57
58use bytemuck::*;
59
60// Re-export so that users don't need to add a bytemuck dependency of their own
61pub use bytemuck;
62
63#[cfg(feature = "serde")]
64use serde_core::{Deserialize, Serialize, ser::SerializeTuple};
65
66#[macro_use]
67mod macros;
68
69macro_rules! pick {
70  ($(if #[cfg($($test:meta),*)] {
71      $($if_tokens:tt)*
72    })else+ else {
73      $($else_tokens:tt)*
74    }) => {
75    pick!{
76      @__forests [ ] ;
77      $( [ {$($test),*} {$($if_tokens)*} ], )*
78      [ { } {$($else_tokens)*} ],
79    }
80  };
81  (if #[cfg($($if_meta:meta),*)] {
82      $($if_tokens:tt)*
83    } $(else if #[cfg($($else_meta:meta),*)] {
84      $($else_tokens:tt)*
85    })*) => {
86    pick!{
87      @__forests [ ] ;
88      [ {$($if_meta),*} {$($if_tokens)*} ],
89      $( [ {$($else_meta),*} {$($else_tokens)*} ], )*
90    }
91  };
92  (@__forests [$($not:meta,)*];) => {
93    /* halt expansion */
94  };
95  (@__forests [$($not:meta,)*]; [{$($m:meta),*} {$($tokens:tt)*}], $($rest:tt)*) => {
96    #[cfg(all( $($m,)* not(any($($not),*)) ))]
97    pick!{ @__identity $($tokens)* }
98    pick!{ @__forests [ $($not,)* $($m,)* ] ; $($rest)* }
99  };
100  (@__identity $($tokens:tt)*) => {
101    $($tokens)*
102  };
103}
104
105// TODO: make these generic over `mul_add`? Worth it?
106
107macro_rules! polynomial_2 {
108  ($x:expr, $c0:expr, $c1:expr, $c2:expr $(,)?) => {{
109    let x = $x;
110    let x2 = x * x;
111    x2.mul_add($c2, x.mul_add($c1, $c0))
112  }};
113}
114
115macro_rules! polynomial_3 {
116  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr $(,)?) => {{
117    let x = $x;
118    let x2 = x * x;
119    $c3.mul_add(x, $c2).mul_add(x2, $c1.mul_add(x, $c0))
120  }};
121}
122
123macro_rules! polynomial_4 {
124  ($x:expr, $c0:expr, $c1:expr, $c2:expr ,$c3:expr, $c4:expr $(,)?) => {{
125    let x = $x;
126    let x2 = x * x;
127    let x4 = x2 * x2;
128    $c3.mul_add(x, $c2).mul_add(x2, $c1.mul_add(x, $c0)) + $c4 * x4
129  }};
130}
131
132macro_rules! polynomial_5 {
133  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr $(,)?) => {{
134    let x = $x;
135    let x2 = x * x;
136    let x4 = x2 * x2;
137    $c3
138      .mul_add(x, $c2)
139      .mul_add(x2, $c5.mul_add(x, $c4).mul_add(x4, $c1.mul_add(x, $c0)))
140  }};
141}
142
143macro_rules! polynomial_5n {
144  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr $(,)?) => {{
145    let x = $x;
146    let x2 = x * x;
147    let x4 = x2 * x2;
148    x2.mul_add(x.mul_add($c3, $c2), (x4.mul_add($c4 + x, x.mul_add($c1, $c0))))
149  }};
150}
151
152macro_rules! polynomial_6 {
153  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr ,$c6:expr $(,)?) => {{
154    let x = $x;
155    let x2 = x * x;
156    let x4 = x2 * x2;
157    x4.mul_add(
158      x2.mul_add($c6, x.mul_add($c5, $c4)),
159      x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0)),
160    )
161  }};
162}
163
164macro_rules! polynomial_6n {
165  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr $(,)?) => {{
166    let x = $x;
167    let x2 = x * x;
168    let x4 = x2 * x2;
169    x4.mul_add(
170      x.mul_add($c5, x2 + $c4),
171      x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0)),
172    )
173  }};
174}
175
176macro_rules! polynomial_7 {
177  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr, $c6:expr, $c7:expr $(,)?) => {{
178    let x = $x;
179    let x2 = x * x;
180    let x4 = x2 * x2;
181    x4.mul_add(
182      x2.mul_add(x.mul_add($c7, $c6), x.mul_add($c5, $c4)),
183      x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0)),
184    )
185  }};
186}
187
188macro_rules! polynomial_8 {
189  ($x:expr, $c0:expr, $c1:expr, $c2:expr, $c3:expr, $c4:expr, $c5:expr,  $c6:expr, $c7:expr, $c8:expr $(,)?) => {{
190    let x = $x;
191    let x2 = x * x;
192    let x4 = x2 * x2;
193    let x8 = x4 * x4;
194    x4.mul_add(
195      x2.mul_add($c7.mul_add(x, $c6), x.mul_add($c5, $c4)),
196      x8.mul_add($c8, x2.mul_add(x.mul_add($c3, $c2), x.mul_add($c1, $c0))),
197    )
198  }};
199}
200
201macro_rules! polynomial_13 {
202  // calculates polynomial c13*x^13 + c12*x^12 + ... + c1*x + c0
203  ($x:expr,  $c2:expr, $c3:expr, $c4:expr, $c5:expr,$c6:expr, $c7:expr, $c8:expr,$c9:expr, $c10:expr, $c11:expr, $c12:expr, $c13:expr  $(,)?) => {{
204    let x = $x;
205    let x2 = x * x;
206    let x4 = x2 * x2;
207    let x8 = x4 * x4;
208    x8.mul_add(
209      x4.mul_add(
210        x.mul_add($c13, $c12),
211        x2.mul_add(x.mul_add($c11, $c10), x.mul_add($c9, $c8)),
212      ),
213      x4.mul_add(
214        x2.mul_add(x.mul_add($c7, $c6), x.mul_add($c5, $c4)),
215        x2.mul_add(x.mul_add($c3, $c2), x),
216      ),
217    )
218  }};
219}
220
221mod f32x16_;
222pub use f32x16_::*;
223
224mod f32x8_;
225pub use f32x8_::*;
226
227mod f32x4_;
228pub use f32x4_::*;
229
230mod f64x8_;
231pub use f64x8_::*;
232
233mod f64x4_;
234pub use f64x4_::*;
235
236mod f64x2_;
237pub use f64x2_::*;
238
239mod i8x16_;
240pub use i8x16_::*;
241
242mod i16x16_;
243pub use i16x16_::*;
244
245mod i16x32_;
246pub use i16x32_::*;
247
248mod i8x32_;
249pub use i8x32_::*;
250
251mod i16x8_;
252pub use i16x8_::*;
253
254mod i32x4_;
255pub use i32x4_::*;
256
257mod i32x8_;
258pub use i32x8_::*;
259
260mod i32x16_;
261pub use i32x16_::*;
262
263mod i64x2_;
264pub use i64x2_::*;
265
266mod i64x4_;
267pub use i64x4_::*;
268
269mod i64x8_;
270pub use i64x8_::*;
271
272mod u8x16_;
273pub use u8x16_::*;
274
275mod u8x32_;
276pub use u8x32_::*;
277
278mod u16x8_;
279pub use u16x8_::*;
280
281mod u16x16_;
282pub use u16x16_::*;
283
284mod u16x32_;
285pub use u16x32_::*;
286
287mod u32x4_;
288pub use u32x4_::*;
289
290mod u32x8_;
291pub use u32x8_::*;
292
293mod u32x16_;
294pub use u32x16_::*;
295
296mod u64x2_;
297pub use u64x2_::*;
298
299mod u64x4_;
300pub use u64x4_::*;
301
302mod u64x8_;
303pub use u64x8_::*;
304
305#[allow(dead_code)]
306fn generic_bit_blend<T>(mask: T, y: T, n: T) -> T
307where
308  T: Copy + BitXor<Output = T> + BitAnd<Output = T>,
309{
310  n ^ ((n ^ y) & mask)
311}
312
313/// given `type.op(type)` and type is `Copy`, impls `type.op(&type)`
314macro_rules! bulk_impl_op_ref_self_for {
315  ($(($op:ident, $method:ident) => [$($t:ty),+]),+ $(,)?) => {
316    $( // do each trait/list matching given
317      $( // do the current trait for each type in its list.
318        impl $op<&Self> for $t {
319          type Output = Self;
320          #[inline]
321          fn $method(self, rhs: &Self) -> Self::Output {
322            self.$method(*rhs)
323          }
324        }
325      )+
326    )+
327  };
328}
329
330bulk_impl_op_ref_self_for! {
331  (Add, add) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
332  (Sub, sub) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
333  (Mul, mul) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
334  (Div, div) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
335  (BitAnd, bitand) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
336  (BitOr, bitor) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
337  (BitXor, bitxor) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
338}
339
340/// given `type.op(rhs)` and type is Copy, impls `type.op_assign(rhs)`
341macro_rules! bulk_impl_op_assign_for {
342  ($(($op:ident<$rhs:ty>, $method:ident, $method_assign:ident) => [$($t:ty),+]),+ $(,)?) => {
343    $( // do each trait/list matching given
344      $( // do the current trait for each type in its list.
345        impl $op<$rhs> for $t {
346          #[inline]
347          fn $method_assign(&mut self, rhs: $rhs) {
348            *self = self.$method(rhs);
349          }
350        }
351      )+
352    )+
353  };
354}
355
356// Note: remember to update bulk_impl_op_ref_self_for first or this will give
357// weird errors!
358bulk_impl_op_assign_for! {
359  (AddAssign<Self>, add, add_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
360  (AddAssign<&Self>, add, add_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
361  (SubAssign<Self>, sub, sub_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
362  (SubAssign<&Self>, sub, sub_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
363  (MulAssign<Self>, mul, mul_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
364  (MulAssign<&Self>, mul, mul_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, u16x8, u16x16, u16x32],
365  (DivAssign<Self>, div, div_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
366  (DivAssign<&Self>, div, div_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2],
367  (BitAndAssign<Self>, bitand, bitand_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
368  (BitAndAssign<&Self>, bitand, bitand_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
369  (BitOrAssign<Self>, bitor, bitor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
370  (BitOrAssign<&Self>, bitor, bitor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
371  (BitXorAssign<Self>, bitxor, bitxor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
372  (BitXorAssign<&Self>, bitxor, bitxor_assign) => [f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, u16x16, u16x32, i32x8, i32x4, i32x16, i64x2, i64x4, i64x8, u8x32, u8x16, u16x8, u32x8, u32x4, u32x16, u64x4, u64x2, u64x8],
373}
374
375macro_rules! impl_integer_neg {
376  ($($t:ty),+ $(,)?) => {
377    $(
378      impl Neg for $t {
379        type Output = Self;
380        #[inline(always)]
381        fn neg(self) -> Self::Output {
382          Self::default() - self
383        }
384      }
385      impl Neg for &'_ $t {
386        type Output = $t;
387        #[inline(always)]
388        fn neg(self) -> Self::Output {
389          <$t>::default() - *self
390        }
391      }
392    )+
393  };
394}
395
396impl_integer_neg! {
397  i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x4, i64x2, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x2, u64x4, u64x8
398}
399
400// only works for 128 bit values
401macro_rules! impl_simple_not {
402  ($($t:ty),+ $(,)?) => {
403    $(
404      impl Not for $t {
405        type Output = Self;
406        #[inline]
407        fn not(self) -> Self::Output {
408          self ^ cast::<u128, $t>(u128::MAX)
409        }
410      }
411    )+
412  };
413}
414
415impl_simple_not! {
416  f32x4, i8x16, i16x8, i32x4, i64x2, u8x16, u16x8, u32x4, u64x2,
417}
418
419macro_rules! impl_not_ref {
420  ($($t:ty),+ $(,)?) => {
421    $(
422      impl Not for &'_ $t {
423        type Output = $t;
424        #[inline]
425        fn not(self) -> Self::Output {
426          !*self
427        }
428      }
429    )+
430  };
431}
432
433impl_not_ref! {
434  f32x4, f32x8, f32x16, f64x2, f64x4, f64x8, i8x16, i8x32, i16x8, i16x16, i16x32, i32x4, i32x8,
435  i32x16, i64x2, i64x4, i64x8, u8x16, u8x32, u16x8, u16x16, u16x32, u32x4, u32x8, u32x16, u64x2,
436  u64x4, u64x8,
437}
438
439macro_rules! impl_simple_sum {
440  ($($t:ty),+ $(,)?) => {
441    $(
442      impl<RHS> core::iter::Sum<RHS> for $t where $t: AddAssign<RHS> {
443        #[inline]
444        fn sum<I: Iterator<Item = RHS>>(iter: I) -> Self {
445          let mut total = Self::zeroed();
446          for val in iter {
447            total += val;
448          }
449          total
450        }
451      }
452    )+
453  };
454}
455
456impl_simple_sum! {
457  f32x16, f32x8, f32x4, f64x8, f64x4, f64x2, i8x32, i8x16, i16x8, i16x16, i16x32, i32x8, i32x4, i32x16, i64x4, i64x2, i64x8, u8x32, u8x16, u16x8, u16x16, u16x32, u32x8, u32x4, u32x16, u64x2, u64x4, u64x8
458}
459
460macro_rules! impl_floating_product {
461  ($($t:ty),+ $(,)?) => {
462    $(
463      impl<RHS> core::iter::Product<RHS> for $t where $t: MulAssign<RHS> {
464        #[inline]
465        fn product<I: Iterator<Item = RHS>>(iter: I) -> Self {
466          let mut total = Self::from(1.0);
467          for val in iter {
468            total *= val;
469          }
470          total
471        }
472      }
473    )+
474  };
475}
476
477impl_floating_product! {
478  f32x16, f32x8, f32x4, f64x8, f64x4, f64x2
479}
480
481macro_rules! impl_integer_product {
482  ($($t:ty),+ $(,)?) => {
483    $(
484      impl<RHS> core::iter::Product<RHS> for $t where $t: MulAssign<RHS> {
485        #[inline]
486        fn product<I: Iterator<Item = RHS>>(iter: I) -> Self {
487          let mut total = Self::from(1);
488          for val in iter {
489            total *= val;
490          }
491          total
492        }
493      }
494    )+
495  };
496}
497
498impl_integer_product! {
499  i16x8, i16x32, i32x4, i32x8, i32x16,
500}
501
502/// impls `From<a> for b` by just calling `cast`
503macro_rules! impl_from_a_for_b_with_cast {
504  ($(($arr:ty, $simd:ty)),+  $(,)?) => {
505    $(impl From<$arr> for $simd {
506      #[inline]
507      fn from(arr: $arr) -> Self {
508        cast(arr)
509      }
510    }
511    impl From<$simd> for $arr {
512      #[inline]
513      fn from(simd: $simd) -> Self {
514        cast(simd)
515      }
516    })+
517  };
518}
519
520impl_from_a_for_b_with_cast! {
521  ([f32;16], f32x16), ([f32;8], f32x8),
522  ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
523  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2), ([i64;4], i64x4), ([i64;8], i64x8),
524  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2), ([u64;4], u64x4), ([u64;8], u64x8),
525}
526
527macro_rules! impl_from_single_value {
528  ($(([$elem:ty;$len:expr], $simd:ty)),+  $(,)?) => {
529    $(impl From<$elem> for $simd {
530      /// Splats the single value given across all lanes.
531      #[inline]
532      fn from(elem: $elem) -> Self {
533        cast([elem; $len])
534      }
535    }
536    impl $simd {
537      #[inline]
538      #[must_use]
539      pub const fn splat(elem: $elem) -> $simd {
540        unsafe { core::mem::transmute([elem; $len]) }
541      }
542    })+
543  };
544}
545
546impl_from_single_value! {
547  ([f32;16], f32x16), ([f32;8], f32x8),
548  ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
549  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2), ([i64;4], i64x4), ([i64;8], i64x8),
550  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2), ([u64;4], u64x4), ([u64;8], u64x8),
551}
552
553/// formatter => [(arr, simd)+],+
554macro_rules! impl_formatter_for {
555  ($($trait:ident => [$(($arr:ty, $simd:ty)),+]),+ $(,)?) => {
556    $( // do per trait
557      $( // do per simd type
558        impl $trait for $simd {
559          #[allow(clippy::missing_inline_in_public_items)]
560          fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
561            let a: $arr = cast(*self);
562            write!(f, "(")?;
563            for (x, a_ref) in a.iter().enumerate() {
564              if x > 0 {
565                write!(f, ", ")?;
566              }
567              $trait::fmt(a_ref, f)?;
568            }
569            write!(f, ")")
570          }
571        }
572      )+
573    )+
574  }
575}
576
577impl_formatter_for! {
578  Binary => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
579  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
580  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
581  Debug => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
582  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
583  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
584  Display => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
585  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
586  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
587  LowerExp => [([f32;16], f32x16), ([f32;8], f32x8), ([f32;4], f32x4), ([f64;8], f64x8), ([f64;4], f64x4), ([f64;2], f64x2),
588  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
589  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
590  LowerHex => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
591  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
592  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
593  Octal => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
594  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
595  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
596  UpperExp => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
597  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
598  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
599  UpperHex => [([u32;16], f32x16), ([u32;8], f32x8), ([u32;4], f32x4), ([u64;8], f64x8), ([u64;4], f64x4), ([u64;2], f64x2),
600  ([i8;32], i8x32), ([i8;16], i8x16), ([i16;8], i16x8), ([i16;16], i16x16), ([i16;32], i16x32), ([i32;8], i32x8), ([i32;4], i32x4), ([i32;16], i32x16), ([i64;2], i64x2),([i64;4], i64x4),([i64;8], i64x8),
601  ([u8;32], u8x32), ([u8;16], u8x16), ([u16;8], u16x8), ([u16;16], u16x16), ([u16;32], u16x32), ([u32;8], u32x8), ([u32;4], u32x4), ([u32;16], u32x16), ([u64;2], u64x2),([u64;4], u64x4),([u64;8], u64x8)],
602}
603
604// With const generics this could be simplified I hope
605macro_rules! from_array {
606  ($ty:ty,$dst:ty,$dst_wide:ident,32) => {
607    impl From<&[$ty]> for $dst_wide {
608      #[inline]
609      fn from(src: &[$ty]) -> $dst_wide {
610        match src.len() {
611          32 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst, src[30] as $dst, src[31] as $dst,]),
612          31 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst, src[30] as $dst,0 as $dst,]),
613          30 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst, src[29] as $dst,0 as $dst,0 as $dst,]),
614          29 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst, src[28] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
615          28 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst, src[27] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
616          27 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst, src[26] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
617          26 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst, src[25] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
618          25 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst, src[24] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
619          24 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst, src[23] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
620          23 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst, src[22] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
621          22 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst, src[21] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
622          21 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst, src[20] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
623          20 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst, src[19] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
624          19 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst, src[18] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
625          18 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst, src[17] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
626          17 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst, src[16] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
627          16 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
628          15 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
629          14 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
630          13 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
631          12 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
632          11 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
633          10 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
634          9 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
635          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
636          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
637          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
638          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
639          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
640          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
641          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
642          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
643          _ => panic!(
644            "Converting from an array larger than what can be stored in $dst_wide"
645          ),
646        }
647      }
648    }
649  };
650  ($ty:ty,$dst:ty,$dst_wide:ident,16) => {
651    impl From<&[$ty]> for $dst_wide {
652      #[inline]
653      fn from(src: &[$ty]) -> $dst_wide {
654        match src.len() {
655          16 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst, src[15] as $dst,]),
656          15 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst, src[14] as $dst,0 as $dst,]),
657          14 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst, src[13] as $dst,0 as $dst,0 as $dst,]),
658          13 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst, src[12] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
659          12 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst, src[11] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
660          11 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst, src[10] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
661          10 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst, src[9] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
662          9 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst, src[8] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
663          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
664          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
665          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
666          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
667          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
668          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
669          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
670          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
671          _ => panic!(
672            "Converting from an array larger than what can be stored in $dst_wide"
673          ),
674        }
675      }
676    }
677  };
678  ($ty:ty,$dst:ty,$dst_wide:ident,8) => {
679    impl From<&[$ty]> for $dst_wide {
680      #[inline]
681      fn from(src: &[$ty]) -> $dst_wide {
682        match src.len() {
683          8 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst, src[7] as $dst,]),
684          7 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst, src[6] as $dst,0 as $dst,]),
685          6 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst, src[5] as $dst,0 as $dst,0 as $dst,]),
686          5 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst, src[4] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
687          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
688          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
689          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
690          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
691          0 => $dst_wide::from([0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,0 as $dst,]),
692          _ => panic!(
693            "Converting from an array larger than what can be stored in $dst_wide"
694          ),
695        }
696      }
697    }
698  };
699  ($ty:ty,$dst:ty,$dst_wide:ident,4) => {
700    impl From<&[$ty]> for $dst_wide {
701      #[inline]
702      fn from(src: &[$ty]) -> $dst_wide {
703        match src.len() {
704          4 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst, src[3] as $dst,]),
705          3 => $dst_wide::from([src[0] as $dst, src[1] as $dst, src[2] as $dst,0 as $dst,]),
706          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst,0 as $dst,0 as $dst,]),
707          1 => $dst_wide::from([src[0] as $dst,0 as $dst,0 as $dst,0 as $dst,]),
708          _ => panic!(
709            "Converting from an array larger than what can be stored in $dst_wide"
710          ),
711        }
712      }
713    }
714  };
715  ($ty:ty,$dst:ty,$dst_wide:ident,2) => {
716    impl From<&[$ty]> for $dst_wide {
717      #[inline]
718      fn from(src: &[$ty]) -> $dst_wide {
719        match src.len() {
720          2 => $dst_wide::from([src[0] as $dst, src[1] as $dst]),
721          1 => $dst_wide::from([src[0] as $dst,0 as $dst]),
722          _ => panic!(
723            "Converting from an array larger than what can be stored in $dst_wide"
724          ),
725        }
726      }
727    }
728  };
729}
730
731from_array!(f32, f32, f32x4, 4);
732from_array!(f32, f32, f32x8, 8);
733from_array!(f32, f32, f32x16, 16);
734from_array!(f64, f64, f64x2, 2);
735from_array!(f64, f64, f64x4, 4);
736from_array!(f64, f64, f64x8, 8);
737from_array!(i8, i8, i8x16, 16);
738from_array!(i8, i8, i8x32, 32);
739from_array!(i16, i16, i16x8, 8);
740from_array!(i16, i16, i16x16, 16);
741from_array!(i16, i16, i16x32, 32);
742from_array!(i32, i32, i32x4, 4);
743from_array!(i32, i32, i32x8, 8);
744from_array!(i32, i32, i32x16, 16);
745from_array!(i64, i64, i64x2, 2);
746from_array!(i64, i64, i64x4, 4);
747from_array!(i64, i64, i64x8, 8);
748from_array!(u8, u8, u8x16, 16);
749from_array!(u8, u8, u8x32, 32);
750from_array!(u16, u16, u16x8, 8);
751from_array!(u16, u16, u16x16, 16);
752from_array!(u16, u16, u16x32, 32);
753from_array!(u32, u32, u32x4, 4);
754from_array!(u32, u32, u32x8, 8);
755from_array!(u32, u32, u32x16, 16);
756from_array!(u64, u64, u64x2, 2);
757from_array!(u64, u64, u64x4, 4);
758from_array!(u64, u64, u64x8, 8);
759from_array!(i8, i32, i32x8, 8);
760
761#[allow(unused)]
762fn software_sqrt(x: f64) -> f64 {
763  use core::num::Wrapping;
764  type wu32 = Wrapping<u32>;
765  const fn w(u: u32) -> wu32 {
766    Wrapping(u)
767  }
768  let mut z: f64;
769  let sign: wu32 = w(0x80000000);
770  let mut ix0: i32;
771  let mut s0: i32;
772  let mut q: i32;
773  let mut m: i32;
774  let mut t: i32;
775  let mut i: i32;
776  let mut r: wu32;
777  let mut t1: wu32;
778  let mut s1: wu32;
779  let mut ix1: wu32;
780  let mut q1: wu32;
781  // extract data
782
783  pick! {
784    if #[cfg(target_endian = "little")]
785    {
786      let [low, high]: [u32; 2] = cast(x);
787      ix0 = high as i32;
788      ix1 = w(low);
789    }
790    else
791    {
792      let [high, low]: [u32; 2] = cast(x);
793      ix0 = high as i32;
794      ix1 = w(low);
795    }
796  }
797
798  // inf and nan
799  {
800    if x.is_nan() {
801      return f64::NAN;
802    }
803    if ix0 & 0x7ff00000 == 0x7ff00000 {
804      return x * x + x;
805    }
806  }
807  // handle zero
808  {
809    if ix0 <= 0 {
810      if ((ix0 & (!sign).0 as i32) | (ix1.0 as i32)) == 0 {
811        return x;
812      } else if ix0 < 0 {
813        return (x - x) / (x - x);
814      }
815    }
816  }
817  // normalize
818  {
819    m = ix0 >> 20;
820    if m == 0 {
821      // subnormal
822      while ix0 == 0 {
823        m -= 21;
824        ix0 |= (ix1 >> 11).0 as i32;
825        ix1 <<= 21;
826      }
827      i = 0;
828      while ix0 & 0x00100000 == 0 {
829        ix0 <<= 1;
830        i += 1;
831      }
832      m -= i - 1;
833      ix0 |= (ix1.0 >> (31 - i)) as i32;
834      ix1 <<= i as usize;
835    }
836    // un-bias exponent
837    m -= 1023;
838    ix0 = (ix0 & 0x000fffff) | 0x00100000;
839    if (m & 1) != 0 {
840      // odd m, double the input to make it even
841      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
842      ix1 += ix1;
843    }
844    m >>= 1;
845  }
846  // generate sqrt bit by bit
847  {
848    ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
849    ix1 += ix1;
850    // q and q1 store the sqrt(x);
851    q = 0;
852    q1 = w(0);
853    s0 = 0;
854    s1 = w(0);
855    // our bit that moves from right to left
856    r = w(0x00200000);
857    while r != w(0) {
858      t = s0 + (r.0 as i32);
859      if t <= ix0 {
860        s0 = t + (r.0 as i32);
861        ix0 -= t;
862        q += (r.0 as i32);
863      }
864      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
865      ix1 += ix1;
866      r >>= 1;
867    }
868    r = sign;
869    while r != w(0) {
870      t1 = s1 + r;
871      t = s0;
872      if (t < ix0) || ((t == ix0) && (t1 <= ix1)) {
873        s1 = t1 + r;
874        if t1 & sign == sign && (s1 & sign) == w(0) {
875          s0 += 1;
876        }
877        ix0 -= t;
878        if ix1 < t1 {
879          ix0 -= 1;
880        }
881        ix1 -= t1;
882        q1 += r;
883      }
884      ix0 += ix0 + ((ix1 & sign) >> 31).0 as i32;
885      ix1 += ix1;
886      r >>= 1;
887    }
888  }
889  // use floating add to find out rounding direction
890  {
891    if ix0 | (ix1.0 as i32) != 0 {
892      z = 1.0 - 1.0e-300;
893      if z >= 1.0 {
894        z = 1.0 + 1.0e-300;
895        if q1 == w(0xffffffff) {
896          q1 = w(0);
897          q += 1;
898        } else if z > 1.0 {
899          if q1 == w(0xfffffffe) {
900            q += 1;
901          }
902          q1 += w(2);
903        } else {
904          q1 += q1 & w(1);
905        }
906      }
907    }
908  }
909  // finish up
910  ix0 = (q >> 1) + 0x3fe00000;
911  ix1 = q1 >> 1;
912  if q & 1 == 1 {
913    ix1 |= sign;
914  }
915  ix0 += m << 20;
916
917  pick! {
918    if #[cfg(target_endian = "little")]
919    {
920      cast::<[u32; 2], f64>([ix1.0, ix0 as u32])
921    }
922    else
923    {
924      cast::<[u32; 2], f64>([ix0 as u32, ix1.0])
925    }
926  }
927}
928
929#[test]
930fn test_software_sqrt() {
931  assert!(software_sqrt(f64::NAN).is_nan());
932  assert_eq!(software_sqrt(f64::INFINITY), f64::INFINITY);
933  assert_eq!(software_sqrt(0.0), 0.0);
934  assert_eq!(software_sqrt(-0.0), -0.0);
935  assert!(software_sqrt(-1.0).is_nan());
936  assert!(software_sqrt(f64::NEG_INFINITY).is_nan());
937  assert_eq!(software_sqrt(4.0), 2.0);
938  assert_eq!(software_sqrt(9.0), 3.0);
939  assert_eq!(software_sqrt(16.0), 4.0);
940  assert_eq!(software_sqrt(25.0), 5.0);
941  assert_eq!(software_sqrt(5000.0 * 5000.0), 5000.0);
942}
943
944#[deprecated(since = "1.5.0", note = "use inherit function instead")]
945pub trait CmpEq<Rhs = Self> {
946  type Output;
947  fn simd_eq(self, rhs: Rhs) -> Self::Output;
948}
949
950#[deprecated(since = "1.5.0", note = "use inherit function instead")]
951pub trait CmpGt<Rhs = Self> {
952  type Output;
953  fn simd_gt(self, rhs: Rhs) -> Self::Output;
954}
955
956#[deprecated(since = "1.5.0", note = "use inherit function instead")]
957pub trait CmpGe<Rhs = Self> {
958  type Output;
959  fn simd_ge(self, rhs: Rhs) -> Self::Output;
960}
961
962#[deprecated(since = "1.5.0", note = "use inherit function instead")]
963pub trait CmpNe<Rhs = Self> {
964  type Output;
965  fn simd_ne(self, rhs: Rhs) -> Self::Output;
966}
967
968#[deprecated(since = "1.5.0", note = "use inherit function instead")]
969pub trait CmpLt<Rhs = Self> {
970  type Output;
971  fn simd_lt(self, rhs: Rhs) -> Self::Output;
972}
973
974#[deprecated(since = "1.5.0", note = "use inherit function instead")]
975pub trait CmpLe<Rhs = Self> {
976  type Output;
977  fn simd_le(self, rhs: Rhs) -> Self::Output;
978}
979pub trait AlignTo
980where
981  Self: Pod + Default + PartialEq + From<Self::Elem>,
982  Self::Elem: Pod + Default + PartialEq,
983{
984  type Elem;
985
986  #[inline]
987  fn simd_align_to(
988    slice: &[Self::Elem],
989  ) -> (&[Self::Elem], &[Self], &[Self::Elem]) {
990    pod_align_to(slice)
991  }
992
993  #[inline]
994  fn simd_align_to_mut(
995    slice: &mut [Self::Elem],
996  ) -> (&mut [Self::Elem], &mut [Self], &mut [Self::Elem]) {
997    pod_align_to_mut(slice)
998  }
999}
1000
1001macro_rules! bulk_impl_const_rhs_op {
1002  (($op:ident, $method:ident) => [$(($lhs:ty, $rhs:ty)),+ $(,)?]) => {
1003    $(
1004    #[expect(deprecated)]
1005    impl $op<$rhs> for $lhs {
1006      type Output = Self;
1007      #[inline]
1008      fn $method(self, rhs: $rhs) -> Self::Output {
1009        self.$method(<$lhs>::splat(rhs))
1010      }
1011    }
1012    )+
1013  };
1014}
1015
1016macro_rules! bulk_impl_const_rhs_ops {
1017  ([$(($lhs:ty, $rhs:ty)),+ $(,)?]) => {
1018    bulk_impl_const_rhs_op!((CmpEq, simd_eq) => [$(($lhs, $rhs)),+]);
1019    bulk_impl_const_rhs_op!((CmpNe, simd_ne) => [$(($lhs, $rhs)),+]);
1020    bulk_impl_const_rhs_op!((CmpLt, simd_lt) => [$(($lhs, $rhs)),+]);
1021    bulk_impl_const_rhs_op!((CmpGt, simd_gt) => [$(($lhs, $rhs)),+]);
1022    bulk_impl_const_rhs_op!((CmpLe, simd_le) => [$(($lhs, $rhs)),+]);
1023    bulk_impl_const_rhs_op!((CmpGe, simd_ge) => [$(($lhs, $rhs)),+]);
1024  };
1025}
1026
1027bulk_impl_const_rhs_ops!([
1028  (f32x4, f32),
1029  (f32x8, f32),
1030  (f32x16, f32),
1031  (f64x2, f64),
1032  (f64x4, f64),
1033  (f64x8, f64),
1034  (i8x16, i8),
1035  (i8x32, i8),
1036  (i16x8, i16),
1037  (i16x16, i16),
1038  (i16x32, i16),
1039  (i32x4, i32),
1040  (i32x8, i32),
1041  (i32x16, i32),
1042  (i64x2, i64),
1043  (i64x4, i64),
1044  (i64x8, i64),
1045  (u8x16, u8),
1046  (u8x32, u8),
1047  (u16x8, u16),
1048  (u16x16, u16),
1049  (u16x32, u16),
1050  (u32x4, u32),
1051  (u32x8, u32),
1052  (u32x16, u32),
1053  (u64x2, u64),
1054  (u64x4, u64),
1055  (u64x8, u64),
1056]);
1057
1058macro_rules! impl_serde {
1059  ($i:ident, [$t:ty; $len:expr]) => {
1060    #[cfg(feature = "serde")]
1061    impl Serialize for $i {
1062      #[inline]
1063      fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1064      where
1065        S: serde_core::Serializer,
1066      {
1067        let array = self.as_array();
1068        let mut seq = serializer.serialize_tuple($len)?;
1069        for e in array {
1070          seq.serialize_element(e)?;
1071        }
1072        seq.end()
1073      }
1074    }
1075
1076    #[cfg(feature = "serde")]
1077    impl<'de> Deserialize<'de> for $i {
1078      #[inline]
1079      fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1080      where
1081        D: serde_core::Deserializer<'de>,
1082      {
1083        Ok(<[$t; $len]>::deserialize(deserializer)?.into())
1084      }
1085    }
1086  };
1087}
1088
1089impl_serde!(f32x8, [f32; 8]);
1090impl_serde!(f32x4, [f32; 4]);
1091impl_serde!(f64x4, [f64; 4]);
1092impl_serde!(f64x2, [f64; 2]);
1093impl_serde!(i8x16, [i8; 16]);
1094impl_serde!(i16x16, [i16; 16]);
1095impl_serde!(i8x32, [i8; 32]);
1096impl_serde!(i16x8, [i16; 8]);
1097impl_serde!(i32x4, [i32; 4]);
1098impl_serde!(i32x8, [i32; 8]);
1099impl_serde!(i64x2, [i64; 2]);
1100impl_serde!(i64x4, [i64; 4]);
1101impl_serde!(u8x16, [u8; 16]);
1102impl_serde!(u8x32, [u8; 32]);
1103impl_serde!(u16x8, [u16; 8]);
1104impl_serde!(u16x16, [u16; 16]);
1105impl_serde!(u32x4, [u32; 4]);
1106impl_serde!(u32x8, [u32; 8]);
1107impl_serde!(u64x2, [u64; 2]);
1108impl_serde!(u64x4, [u64; 4]);
1109impl_serde!(u64x8, [u64; 8]);
1110impl_serde!(i64x8, [i64; 8]);
1111impl_serde!(i16x32, [i16; 32]);
1112impl_serde!(u16x32, [u16; 32]);
1113impl_serde!(i32x16, [i32; 16]);
1114impl_serde!(u32x16, [u32; 16]);
1115impl_serde!(f32x16, [f32; 16]);
1116impl_serde!(f64x8, [f64; 8]);