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 "C" {
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}