[go: up one dir, main page]

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