#
core/stdarch/crates/core_arch/src/wasm32/
relaxed_simd.rs

    1use super::v128;
    2use crate::core_arch::simd;
    3
    4#[cfg(test)]
    5use stdarch_test::assert_instr;
    6
    7#[allow(improper_ctypes)]
    8unsafe extern "unadjusted" {
    9    #[link_name = "llvm.wasm.relaxed.swizzle"]
    10    fn llvm_relaxed_swizzle(a: simd::i8x16, b: simd::i8x16) -> simd::i8x16;
    11    #[link_name = "llvm.wasm.relaxed.trunc.signed"]
    12    fn llvm_relaxed_trunc_signed(a: simd::f32x4) -> simd::i32x4;
    13    #[link_name = "llvm.wasm.relaxed.trunc.unsigned"]
    14    fn llvm_relaxed_trunc_unsigned(a: simd::f32x4) -> simd::i32x4;
    15    #[link_name = "llvm.wasm.relaxed.trunc.signed.zero"]
    16    fn llvm_relaxed_trunc_signed_zero(a: simd::f64x2) -> simd::i32x4;
    17    #[link_name = "llvm.wasm.relaxed.trunc.unsigned.zero"]
    18    fn llvm_relaxed_trunc_unsigned_zero(a: simd::f64x2) -> simd::i32x4;
    19
    20    #[link_name = "llvm.wasm.relaxed.madd.v4f32"]
    21    fn llvm_f32x4_fma(a: simd::f32x4, b: simd::f32x4, c: simd::f32x4) -> simd::f32x4;
    22    #[link_name = "llvm.wasm.relaxed.nmadd.v4f32"]
    23    fn llvm_f32x4_fms(a: simd::f32x4, b: simd::f32x4, c: simd::f32x4) -> simd::f32x4;
    24    #[link_name = "llvm.wasm.relaxed.madd.v2f64"]
    25    fn llvm_f64x2_fma(a: simd::f64x2, b: simd::f64x2, c: simd::f64x2) -> simd::f64x2;
    26    #[link_name = "llvm.wasm.relaxed.nmadd.v2f64"]
    27    fn llvm_f64x2_fms(a: simd::f64x2, b: simd::f64x2, c: simd::f64x2) -> simd::f64x2;
    28
    29    #[link_name = "llvm.wasm.relaxed.laneselect.v16i8"]
    30    fn llvm_i8x16_laneselect(a: simd::i8x16, b: simd::i8x16, c: simd::i8x16) -> simd::i8x16;
    31    #[link_name = "llvm.wasm.relaxed.laneselect.v8i16"]
    32    fn llvm_i16x8_laneselect(a: simd::i16x8, b: simd::i16x8, c: simd::i16x8) -> simd::i16x8;
    33    #[link_name = "llvm.wasm.relaxed.laneselect.v4i32"]
    34    fn llvm_i32x4_laneselect(a: simd::i32x4, b: simd::i32x4, c: simd::i32x4) -> simd::i32x4;
    35    #[link_name = "llvm.wasm.relaxed.laneselect.v2i64"]
    36    fn llvm_i64x2_laneselect(a: simd::i64x2, b: simd::i64x2, c: simd::i64x2) -> simd::i64x2;
    37
    38    #[link_name = "llvm.wasm.relaxed.min.v4f32"]
    39    fn llvm_f32x4_relaxed_min(a: simd::f32x4, b: simd::f32x4) -> simd::f32x4;
    40    #[link_name = "llvm.wasm.relaxed.min.v2f64"]
    41    fn llvm_f64x2_relaxed_min(a: simd::f64x2, b: simd::f64x2) -> simd::f64x2;
    42    #[link_name = "llvm.wasm.relaxed.max.v4f32"]
    43    fn llvm_f32x4_relaxed_max(a: simd::f32x4, b: simd::f32x4) -> simd::f32x4;
    44    #[link_name = "llvm.wasm.relaxed.max.v2f64"]
    45    fn llvm_f64x2_relaxed_max(a: simd::f64x2, b: simd::f64x2) -> simd::f64x2;
    46
    47    #[link_name = "llvm.wasm.relaxed.q15mulr.signed"]
    48    fn llvm_relaxed_q15mulr_signed(a: simd::i16x8, b: simd::i16x8) -> simd::i16x8;
    49    #[link_name = "llvm.wasm.relaxed.dot.i8x16.i7x16.signed"]
    50    fn llvm_i16x8_relaxed_dot_i8x16_i7x16_s(a: simd::i8x16, b: simd::i8x16) -> simd::i16x8;
    51    #[link_name = "llvm.wasm.relaxed.dot.i8x16.i7x16.add.signed"]
    52    fn llvm_i32x4_relaxed_dot_i8x16_i7x16_add_s(
    53        a: simd::i8x16,
    54        b: simd::i8x16,
    55        c: simd::i32x4,
    56    ) -> simd::i32x4;
    57}
    58
    59/// A relaxed version of `i8x16_swizzle(a, s)` which selects lanes from `a`
    60/// using indices in `s`.
    61///
    62/// Indices in the range `[0,15]` will select the `i`-th element of `a`.
    63/// If the high bit of any element of `s` is set (meaning 128 or greater) then
    64/// the corresponding output lane is guaranteed to be zero. Otherwise if the
    65/// element of `s` is within the range `[16,128)` then the output lane is either
    66/// 0 or `a[s[i] % 16]` depending on the implementation.
    67#[inline]
    68#[cfg_attr(test, assert_instr(i8x16.relaxed_swizzle))]
    69#[target_feature(enable = "relaxed-simd")]
    70#[doc(alias("i8x16.relaxed_swizzle"))]
    71#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    72pub fn i8x16_relaxed_swizzle(a: v128, s: v128) -> v128 {
    73    unsafe { llvm_relaxed_swizzle(a.as_i8x16(), s.as_i8x16()).v128() }
    74}
    75
    76#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    77pub use i8x16_relaxed_swizzle as u8x16_relaxed_swizzle;
    78
    79/// A relaxed version of `i32x4_trunc_sat_f32x4(a)` converts the `f32` lanes
    80/// of `a` to signed 32-bit integers.
    81///
    82/// Values which don't fit in 32-bit integers or are NaN may have the same
    83/// result as `i32x4_trunc_sat_f32x4` or may return `i32::MIN`.
    84#[inline]
    85#[cfg_attr(test, assert_instr(i32x4.relaxed_trunc_f32x4_s))]
    86#[target_feature(enable = "relaxed-simd")]
    87#[doc(alias("i32x4.relaxed_trunc_f32x4_s"))]
    88#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    89pub fn i32x4_relaxed_trunc_f32x4(a: v128) -> v128 {
    90    unsafe { llvm_relaxed_trunc_signed(a.as_f32x4()).v128() }
    91}
    92
    93/// A relaxed version of `u32x4_trunc_sat_f32x4(a)` converts the `f32` lanes
    94/// of `a` to unsigned 32-bit integers.
    95///
    96/// Values which don't fit in 32-bit unsigned integers or are NaN may have the
    97/// same result as `u32x4_trunc_sat_f32x4` or may return `u32::MAX`.
    98#[inline]
    99#[cfg_attr(test, assert_instr(i32x4.relaxed_trunc_f32x4_u))]
    100#[target_feature(enable = "relaxed-simd")]
    101#[doc(alias("i32x4.relaxed_trunc_f32x4_u"))]
    102#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    103pub fn u32x4_relaxed_trunc_f32x4(a: v128) -> v128 {
    104    unsafe { llvm_relaxed_trunc_unsigned(a.as_f32x4()).v128() }
    105}
    106
    107/// A relaxed version of `i32x4_trunc_sat_f64x2_zero(a)` converts the `f64`
    108/// lanes of `a` to signed 32-bit integers and the upper two lanes are zero.
    109///
    110/// Values which don't fit in 32-bit integers or are NaN may have the same
    111/// result as `i32x4_trunc_sat_f32x4` or may return `i32::MIN`.
    112#[inline]
    113#[cfg_attr(test, assert_instr(i32x4.relaxed_trunc_f64x2_s_zero))]
    114#[target_feature(enable = "relaxed-simd")]
    115#[doc(alias("i32x4.relaxed_trunc_f64x2_s_zero"))]
    116#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    117pub fn i32x4_relaxed_trunc_f64x2_zero(a: v128) -> v128 {
    118    unsafe { llvm_relaxed_trunc_signed_zero(a.as_f64x2()).v128() }
    119}
    120
    121/// A relaxed version of `u32x4_trunc_sat_f64x2_zero(a)` converts the `f64`
    122/// lanes of `a` to unsigned 32-bit integers and the upper two lanes are zero.
    123///
    124/// Values which don't fit in 32-bit unsigned integers or are NaN may have the
    125/// same result as `u32x4_trunc_sat_f32x4` or may return `u32::MAX`.
    126#[inline]
    127#[cfg_attr(test, assert_instr(i32x4.relaxed_trunc_f64x2_u_zero))]
    128#[target_feature(enable = "relaxed-simd")]
    129#[doc(alias("i32x4.relaxed_trunc_f64x2_u_zero"))]
    130#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    131pub fn u32x4_relaxed_trunc_f64x2_zero(a: v128) -> v128 {
    132    unsafe { llvm_relaxed_trunc_unsigned_zero(a.as_f64x2()).v128() }
    133}
    134
    135/// Computes `a * b + c` with either one rounding or two roundings.
    136#[inline]
    137#[cfg_attr(test, assert_instr(f32x4.relaxed_madd))]
    138#[target_feature(enable = "relaxed-simd")]
    139#[doc(alias("f32x4.relaxed_madd"))]
    140#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    141pub fn f32x4_relaxed_madd(a: v128, b: v128, c: v128) -> v128 {
    142    unsafe { llvm_f32x4_fma(a.as_f32x4(), b.as_f32x4(), c.as_f32x4()).v128() }
    143}
    144
    145/// Computes `-a * b + c` with either one rounding or two roundings.
    146#[inline]
    147#[cfg_attr(test, assert_instr(f32x4.relaxed_nmadd))]
    148#[target_feature(enable = "relaxed-simd")]
    149#[doc(alias("f32x4.relaxed_nmadd"))]
    150#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    151pub fn f32x4_relaxed_nmadd(a: v128, b: v128, c: v128) -> v128 {
    152    unsafe { llvm_f32x4_fms(a.as_f32x4(), b.as_f32x4(), c.as_f32x4()).v128() }
    153}
    154
    155/// Computes `a * b + c` with either one rounding or two roundings.
    156#[inline]
    157#[cfg_attr(test, assert_instr(f64x2.relaxed_madd))]
    158#[target_feature(enable = "relaxed-simd")]
    159#[doc(alias("f64x2.relaxed_madd"))]
    160#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    161pub fn f64x2_relaxed_madd(a: v128, b: v128, c: v128) -> v128 {
    162    unsafe { llvm_f64x2_fma(a.as_f64x2(), b.as_f64x2(), c.as_f64x2()).v128() }
    163}
    164
    165/// Computes `-a * b + c` with either one rounding or two roundings.
    166#[inline]
    167#[cfg_attr(test, assert_instr(f64x2.relaxed_nmadd))]
    168#[target_feature(enable = "relaxed-simd")]
    169#[doc(alias("f64x2.relaxed_nmadd"))]
    170#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    171pub fn f64x2_relaxed_nmadd(a: v128, b: v128, c: v128) -> v128 {
    172    unsafe { llvm_f64x2_fms(a.as_f64x2(), b.as_f64x2(), c.as_f64x2()).v128() }
    173}
    174
    175/// A relaxed version of `v128_bitselect` where this either behaves the same as
    176/// `v128_bitselect` or the high bit of each lane `m` is inspected and the
    177/// corresponding lane of `a` is chosen if the bit is 1 or the lane of `b` is
    178/// chosen if it's zero.
    179///
    180/// If the `m` mask's lanes are either all-one or all-zero then this instruction
    181/// is the same as `v128_bitselect`.
    182#[inline]
    183#[cfg_attr(test, assert_instr(i8x16.relaxed_laneselect))]
    184#[target_feature(enable = "relaxed-simd")]
    185#[doc(alias("i8x16.relaxed_laneselect"))]
    186#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    187pub fn i8x16_relaxed_laneselect(a: v128, b: v128, m: v128) -> v128 {
    188    unsafe { llvm_i8x16_laneselect(a.as_i8x16(), b.as_i8x16(), m.as_i8x16()).v128() }
    189}
    190
    191#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    192pub use i8x16_relaxed_laneselect as u8x16_relaxed_laneselect;
    193
    194/// A relaxed version of `v128_bitselect` where this either behaves the same as
    195/// `v128_bitselect` or the high bit of each lane `m` is inspected and the
    196/// corresponding lane of `a` is chosen if the bit is 1 or the lane of `b` is
    197/// chosen if it's zero.
    198///
    199/// If the `m` mask's lanes are either all-one or all-zero then this instruction
    200/// is the same as `v128_bitselect`.
    201#[inline]
    202#[cfg_attr(test, assert_instr(i16x8.relaxed_laneselect))]
    203#[target_feature(enable = "relaxed-simd")]
    204#[doc(alias("i16x8.relaxed_laneselect"))]
    205#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    206pub fn i16x8_relaxed_laneselect(a: v128, b: v128, m: v128) -> v128 {
    207    unsafe { llvm_i16x8_laneselect(a.as_i16x8(), b.as_i16x8(), m.as_i16x8()).v128() }
    208}
    209
    210#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    211pub use i16x8_relaxed_laneselect as u16x8_relaxed_laneselect;
    212
    213/// A relaxed version of `v128_bitselect` where this either behaves the same as
    214/// `v128_bitselect` or the high bit of each lane `m` is inspected and the
    215/// corresponding lane of `a` is chosen if the bit is 1 or the lane of `b` is
    216/// chosen if it's zero.
    217///
    218/// If the `m` mask's lanes are either all-one or all-zero then this instruction
    219/// is the same as `v128_bitselect`.
    220#[inline]
    221#[cfg_attr(test, assert_instr(i32x4.relaxed_laneselect))]
    222#[target_feature(enable = "relaxed-simd")]
    223#[doc(alias("i32x4.relaxed_laneselect"))]
    224#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    225pub fn i32x4_relaxed_laneselect(a: v128, b: v128, m: v128) -> v128 {
    226    unsafe { llvm_i32x4_laneselect(a.as_i32x4(), b.as_i32x4(), m.as_i32x4()).v128() }
    227}
    228
    229#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    230pub use i32x4_relaxed_laneselect as u32x4_relaxed_laneselect;
    231
    232/// A relaxed version of `v128_bitselect` where this either behaves the same as
    233/// `v128_bitselect` or the high bit of each lane `m` is inspected and the
    234/// corresponding lane of `a` is chosen if the bit is 1 or the lane of `b` is
    235/// chosen if it's zero.
    236///
    237/// If the `m` mask's lanes are either all-one or all-zero then this instruction
    238/// is the same as `v128_bitselect`.
    239#[inline]
    240#[cfg_attr(test, assert_instr(i64x2.relaxed_laneselect))]
    241#[target_feature(enable = "relaxed-simd")]
    242#[doc(alias("i64x2.relaxed_laneselect"))]
    243#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    244pub fn i64x2_relaxed_laneselect(a: v128, b: v128, m: v128) -> v128 {
    245    unsafe { llvm_i64x2_laneselect(a.as_i64x2(), b.as_i64x2(), m.as_i64x2()).v128() }
    246}
    247
    248#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    249pub use i64x2_relaxed_laneselect as u64x2_relaxed_laneselect;
    250
    251/// A relaxed version of `f32x4_min` which is either `f32x4_min` or
    252/// `f32x4_pmin`.
    253#[inline]
    254#[cfg_attr(test, assert_instr(f32x4.relaxed_min))]
    255#[target_feature(enable = "relaxed-simd")]
    256#[doc(alias("f32x4.relaxed_min"))]
    257#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    258pub fn f32x4_relaxed_min(a: v128, b: v128) -> v128 {
    259    unsafe { llvm_f32x4_relaxed_min(a.as_f32x4(), b.as_f32x4()).v128() }
    260}
    261
    262/// A relaxed version of `f32x4_max` which is either `f32x4_max` or
    263/// `f32x4_pmax`.
    264#[inline]
    265#[cfg_attr(test, assert_instr(f32x4.relaxed_max))]
    266#[target_feature(enable = "relaxed-simd")]
    267#[doc(alias("f32x4.relaxed_max"))]
    268#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    269pub fn f32x4_relaxed_max(a: v128, b: v128) -> v128 {
    270    unsafe { llvm_f32x4_relaxed_max(a.as_f32x4(), b.as_f32x4()).v128() }
    271}
    272
    273/// A relaxed version of `f64x2_min` which is either `f64x2_min` or
    274/// `f64x2_pmin`.
    275#[inline]
    276#[cfg_attr(test, assert_instr(f64x2.relaxed_min))]
    277#[target_feature(enable = "relaxed-simd")]
    278#[doc(alias("f64x2.relaxed_min"))]
    279#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    280pub fn f64x2_relaxed_min(a: v128, b: v128) -> v128 {
    281    unsafe { llvm_f64x2_relaxed_min(a.as_f64x2(), b.as_f64x2()).v128() }
    282}
    283
    284/// A relaxed version of `f64x2_max` which is either `f64x2_max` or
    285/// `f64x2_pmax`.
    286#[inline]
    287#[cfg_attr(test, assert_instr(f64x2.relaxed_max))]
    288#[target_feature(enable = "relaxed-simd")]
    289#[doc(alias("f64x2.relaxed_max"))]
    290#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    291pub fn f64x2_relaxed_max(a: v128, b: v128) -> v128 {
    292    unsafe { llvm_f64x2_relaxed_max(a.as_f64x2(), b.as_f64x2()).v128() }
    293}
    294
    295/// A relaxed version of `i16x8_relaxed_q15mulr` where if both lanes are
    296/// `i16::MIN` then the result is either `i16::MIN` or `i16::MAX`.
    297#[inline]
    298#[cfg_attr(test, assert_instr(i16x8.relaxed_q15mulr_s))]
    299#[target_feature(enable = "relaxed-simd")]
    300#[doc(alias("i16x8.relaxed_q15mulr_s"))]
    301#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    302pub fn i16x8_relaxed_q15mulr(a: v128, b: v128) -> v128 {
    303    unsafe { llvm_relaxed_q15mulr_signed(a.as_i16x8(), b.as_i16x8()).v128() }
    304}
    305
    306#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    307pub use i16x8_relaxed_q15mulr as u16x8_relaxed_q15mulr;
    308
    309/// A relaxed dot-product instruction.
    310///
    311/// This instruction will perform pairwise products of the 8-bit values in `a`
    312/// and `b` and then accumulate adjacent pairs into 16-bit results producing a
    313/// final `i16x8` vector. The bytes of `a` are always interpreted as signed and
    314/// the bytes in `b` may be interpreted as signed or unsigned. If the top bit in
    315/// `b` isn't set then the value is the same regardless of whether it's signed
    316/// or unsigned.
    317///
    318/// The accumulation into 16-bit values may be saturated on some platforms, and
    319/// on other platforms it may wrap-around on overflow.
    320#[inline]
    321#[cfg_attr(test, assert_instr(i16x8.relaxed_dot_i8x16_i7x16_s))]
    322#[target_feature(enable = "relaxed-simd")]
    323#[doc(alias("i16x8.relaxed_dot_i8x16_i7x16_s"))]
    324#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    325pub fn i16x8_relaxed_dot_i8x16_i7x16(a: v128, b: v128) -> v128 {
    326    unsafe { llvm_i16x8_relaxed_dot_i8x16_i7x16_s(a.as_i8x16(), b.as_i8x16()).v128() }
    327}
    328
    329#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    330pub use i16x8_relaxed_dot_i8x16_i7x16 as u16x8_relaxed_dot_i8x16_i7x16;
    331
    332/// Similar to [`i16x8_relaxed_dot_i8x16_i7x16`] except that the intermediate
    333/// `i16x8` result is fed into `i32x4_extadd_pairwise_i16x8` followed by
    334/// `i32x4_add` to add the value `c` to the result.
    335#[inline]
    336#[cfg_attr(test, assert_instr(i32x4.relaxed_dot_i8x16_i7x16_add_s))]
    337#[target_feature(enable = "relaxed-simd")]
    338#[doc(alias("i32x4.relaxed_dot_i8x16_i7x16_add_s"))]
    339#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    340pub fn i32x4_relaxed_dot_i8x16_i7x16_add(a: v128, b: v128, c: v128) -> v128 {
    341    unsafe {
    342        llvm_i32x4_relaxed_dot_i8x16_i7x16_add_s(a.as_i8x16(), b.as_i8x16(), c.as_i32x4()).v128()
    343    }
    344}
    345
    346#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
    347pub use i32x4_relaxed_dot_i8x16_i7x16_add as u32x4_relaxed_dot_i8x16_i7x16_add;
    348
    349#[cfg(test)]
    350mod tests {
    351    use super::super::simd128::*;
    352    use super::*;
    353    use core::ops::{Add, Div, Mul, Neg, Sub};
    354
    355    use std::fmt::Debug;
    356    use std::mem::transmute;
    357    use std::num::Wrapping;
    358    use std::prelude::v1::*;
    359
    360    fn compare_bytes(a: v128, b: &[v128]) {
    361        let a: [u8; 16] = unsafe { transmute(a) };
    362        if b.iter().any(|b| {
    363            let b: [u8; 16] = unsafe { transmute(*b) };
    364            a == b
    365        }) {
    366            return;
    367        }
    368        eprintln!("input vector {a:?}");
    369        eprintln!("did not match any output:");
    370        for b in b {
    371            eprintln!("  {b:?}");
    372        }
    373    }
    374
    375    #[test]
    376    fn test_relaxed_swizzle() {
    377        compare_bytes(
    378            i8x16_relaxed_swizzle(
    379                i8x16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
    380                i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1),
    381            ),
    382            &[i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1)],
    383        );
    384        compare_bytes(
    385            i8x16_relaxed_swizzle(
    386                i8x16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
    387                u8x16(0x80, 0xff, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    388            ),
    389            &[
    390                i8x16(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    391                i8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    392            ],
    393        );
    394        compare_bytes(
    395            u8x16_relaxed_swizzle(
    396                u8x16(
    397                    128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
    398                ),
    399                u8x16(0x80, 0xff, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
    400            ),
    401            &[
    402                u8x16(
    403                    128, 128, 128, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
    404                ),
    405                u8x16(
    406                    0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
    407                ),
    408            ],
    409        );
    410    }
    411
    412    #[test]
    413    fn test_relaxed_trunc() {
    414        compare_bytes(
    415            i32x4_relaxed_trunc_f32x4(f32x4(1.0, 2.0, -1., -4.)),
    416            &[i32x4(1, 2, -1, -4)],
    417        );
    418        compare_bytes(
    419            i32x4_relaxed_trunc_f32x4(f32x4(f32::NEG_INFINITY, f32::NAN, -0.0, f32::INFINITY)),
    420            &[
    421                i32x4(i32::MIN, 0, 0, i32::MAX),
    422                i32x4(i32::MIN, i32::MIN, 0, i32::MIN),
    423            ],
    424        );
    425        compare_bytes(
    426            i32x4_relaxed_trunc_f64x2_zero(f64x2(1.0, -3.0)),
    427            &[i32x4(1, -3, 0, 0)],
    428        );
    429        compare_bytes(
    430            i32x4_relaxed_trunc_f64x2_zero(f64x2(f64::INFINITY, f64::NAN)),
    431            &[i32x4(i32::MAX, 0, 0, 0), i32x4(i32::MIN, i32::MIN, 0, 0)],
    432        );
    433
    434        compare_bytes(
    435            u32x4_relaxed_trunc_f32x4(f32x4(1.0, 2.0, 5., 100.)),
    436            &[i32x4(1, 2, 5, 100)],
    437        );
    438        compare_bytes(
    439            u32x4_relaxed_trunc_f32x4(f32x4(f32::NEG_INFINITY, f32::NAN, -0.0, f32::INFINITY)),
    440            &[
    441                u32x4(u32::MAX, 0, 0, u32::MAX),
    442                u32x4(u32::MAX, u32::MAX, 0, u32::MAX),
    443            ],
    444        );
    445        compare_bytes(
    446            u32x4_relaxed_trunc_f64x2_zero(f64x2(1.0, 3.0)),
    447            &[u32x4(1, 3, 0, 0)],
    448        );
    449        compare_bytes(
    450            u32x4_relaxed_trunc_f64x2_zero(f64x2(f64::INFINITY, f64::NAN)),
    451            &[i32x4(i32::MAX, 0, 0, 0), i32x4(i32::MIN, i32::MIN, 0, 0)],
    452        );
    453    }
    454
    455    #[test]
    456    fn test_madd() {
    457        let floats = [
    458            f32::NAN,
    459            f32::NEG_INFINITY,
    460            f32::INFINITY,
    461            1.0,
    462            2.0,
    463            -1.0,
    464            0.0,
    465            100.3,
    466            7.8,
    467            9.4,
    468        ];
    469        for &a in floats.iter() {
    470            for &b in floats.iter() {
    471                for &c in floats.iter() {
    472                    let f1 = a * b + c;
    473                    let f2 = a.mul_add(b, c);
    474                    compare_bytes(
    475                        f32x4_relaxed_madd(f32x4(a, a, a, a), f32x4(b, b, b, b), f32x4(c, c, c, c)),
    476                        &[f32x4(f1, f1, f1, f1), f32x4(f2, f2, f2, f2)],
    477                    );
    478
    479                    let f1 = -a * b + c;
    480                    let f2 = (-a).mul_add(b, c);
    481                    compare_bytes(
    482                        f32x4_relaxed_nmadd(
    483                            f32x4(a, a, a, a),
    484                            f32x4(b, b, b, b),
    485                            f32x4(c, c, c, c),
    486                        ),
    487                        &[f32x4(f1, f1, f1, f1), f32x4(f2, f2, f2, f2)],
    488                    );
    489
    490                    let a = f64::from(a);
    491                    let b = f64::from(b);
    492                    let c = f64::from(c);
    493                    let f1 = a * b + c;
    494                    let f2 = a.mul_add(b, c);
    495                    compare_bytes(
    496                        f64x2_relaxed_madd(f64x2(a, a), f64x2(b, b), f64x2(c, c)),
    497                        &[f64x2(f1, f1), f64x2(f2, f2)],
    498                    );
    499                    let f1 = -a * b + c;
    500                    let f2 = (-a).mul_add(b, c);
    501                    compare_bytes(
    502                        f64x2_relaxed_nmadd(f64x2(a, a), f64x2(b, b), f64x2(c, c)),
    503                        &[f64x2(f1, f1), f64x2(f2, f2)],
    504                    );
    505                }
    506            }
    507        }
    508    }
    509}