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 has implementation-specific behavior
252/// when its operands are NaN or signed zeroes. For more information, see [the
253/// WebAssembly
254/// specification](https://webassembly.github.io/spec/core/exec/numerics.html#op-frelaxed-min).
255#[inline]
256#[cfg_attr(test, assert_instr(f32x4.relaxed_min))]
257#[target_feature(enable = "relaxed-simd")]
258#[doc(alias("f32x4.relaxed_min"))]
259#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
260pub fn f32x4_relaxed_min(a: v128, b: v128) -> v128 {
261    unsafe { llvm_f32x4_relaxed_min(a.as_f32x4(), b.as_f32x4()).v128() }
262}
263
264/// A relaxed version of `f32x4_max` which has implementation-specific behavior
265/// when its operands are NaN or signed zeroes. For more information, see [the
266/// WebAssembly
267/// specification](https://webassembly.github.io/spec/core/exec/numerics.html#op-frelaxed-max).
268#[inline]
269#[cfg_attr(test, assert_instr(f32x4.relaxed_max))]
270#[target_feature(enable = "relaxed-simd")]
271#[doc(alias("f32x4.relaxed_max"))]
272#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
273pub fn f32x4_relaxed_max(a: v128, b: v128) -> v128 {
274    unsafe { llvm_f32x4_relaxed_max(a.as_f32x4(), b.as_f32x4()).v128() }
275}
276
277/// A relaxed version of `f64x2_min` which has implementation-specific behavior
278/// when its operands are NaN or signed zeroes. For more information, see [the
279/// WebAssembly
280/// specification](https://webassembly.github.io/spec/core/exec/numerics.html#op-frelaxed-min).
281#[inline]
282#[cfg_attr(test, assert_instr(f64x2.relaxed_min))]
283#[target_feature(enable = "relaxed-simd")]
284#[doc(alias("f64x2.relaxed_min"))]
285#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
286pub fn f64x2_relaxed_min(a: v128, b: v128) -> v128 {
287    unsafe { llvm_f64x2_relaxed_min(a.as_f64x2(), b.as_f64x2()).v128() }
288}
289
290/// A relaxed version of `f64x2_max` which has implementation-specific behavior
291/// when its operands are NaN or signed zeroes. For more information, see [the
292/// WebAssembly
293/// specification](https://webassembly.github.io/spec/core/exec/numerics.html#op-frelaxed-max).
294#[inline]
295#[cfg_attr(test, assert_instr(f64x2.relaxed_max))]
296#[target_feature(enable = "relaxed-simd")]
297#[doc(alias("f64x2.relaxed_max"))]
298#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
299pub fn f64x2_relaxed_max(a: v128, b: v128) -> v128 {
300    unsafe { llvm_f64x2_relaxed_max(a.as_f64x2(), b.as_f64x2()).v128() }
301}
302
303/// A relaxed version of `i16x8_relaxed_q15mulr` where if both lanes are
304/// `i16::MIN` then the result is either `i16::MIN` or `i16::MAX`.
305#[inline]
306#[cfg_attr(test, assert_instr(i16x8.relaxed_q15mulr_s))]
307#[target_feature(enable = "relaxed-simd")]
308#[doc(alias("i16x8.relaxed_q15mulr_s"))]
309#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
310pub fn i16x8_relaxed_q15mulr(a: v128, b: v128) -> v128 {
311    unsafe { llvm_relaxed_q15mulr_signed(a.as_i16x8(), b.as_i16x8()).v128() }
312}
313
314#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
315pub use i16x8_relaxed_q15mulr as u16x8_relaxed_q15mulr;
316
317/// A relaxed dot-product instruction.
318///
319/// This instruction will perform pairwise products of the 8-bit values in `a`
320/// and `b` and then accumulate adjacent pairs into 16-bit results producing a
321/// final `i16x8` vector. The bytes of `a` are always interpreted as signed and
322/// the bytes in `b` may be interpreted as signed or unsigned. If the top bit in
323/// `b` isn't set then the value is the same regardless of whether it's signed
324/// or unsigned.
325///
326/// The accumulation into 16-bit values may be saturated on some platforms, and
327/// on other platforms it may wrap-around on overflow.
328#[inline]
329#[cfg_attr(test, assert_instr(i16x8.relaxed_dot_i8x16_i7x16_s))]
330#[target_feature(enable = "relaxed-simd")]
331#[doc(alias("i16x8.relaxed_dot_i8x16_i7x16_s"))]
332#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
333pub fn i16x8_relaxed_dot_i8x16_i7x16(a: v128, b: v128) -> v128 {
334    unsafe { llvm_i16x8_relaxed_dot_i8x16_i7x16_s(a.as_i8x16(), b.as_i8x16()).v128() }
335}
336
337#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
338pub use i16x8_relaxed_dot_i8x16_i7x16 as u16x8_relaxed_dot_i8x16_i7x16;
339
340/// Similar to [`i16x8_relaxed_dot_i8x16_i7x16`] except that the intermediate
341/// `i16x8` result is fed into `i32x4_extadd_pairwise_i16x8` followed by
342/// `i32x4_add` to add the value `c` to the result.
343#[inline]
344#[cfg_attr(test, assert_instr(i32x4.relaxed_dot_i8x16_i7x16_add_s))]
345#[target_feature(enable = "relaxed-simd")]
346#[doc(alias("i32x4.relaxed_dot_i8x16_i7x16_add_s"))]
347#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
348pub fn i32x4_relaxed_dot_i8x16_i7x16_add(a: v128, b: v128, c: v128) -> v128 {
349    unsafe {
350        llvm_i32x4_relaxed_dot_i8x16_i7x16_add_s(a.as_i8x16(), b.as_i8x16(), c.as_i32x4()).v128()
351    }
352}
353
354#[stable(feature = "stdarch_wasm_relaxed_simd", since = "1.82.0")]
355pub use i32x4_relaxed_dot_i8x16_i7x16_add as u32x4_relaxed_dot_i8x16_i7x16_add;
356
357#[cfg(test)]
358mod tests {
359    use super::super::simd128::*;
360    use super::*;
361    use core::ops::{Add, Div, Mul, Neg, Sub};
362
363    use std::fmt::Debug;
364    use std::mem::transmute;
365    use std::num::Wrapping;
366    use std::prelude::v1::*;
367
368    fn compare_bytes(a: v128, b: &[v128]) {
369        let a: [u8; 16] = unsafe { transmute(a) };
370        if b.iter().any(|b| {
371            let b: [u8; 16] = unsafe { transmute(*b) };
372            a == b
373        }) {
374            return;
375        }
376        eprintln!("input vector {a:?}");
377        eprintln!("did not match any output:");
378        for b in b {
379            eprintln!("  {b:?}");
380        }
381    }
382
383    #[test]
384    fn test_relaxed_swizzle() {
385        compare_bytes(
386            i8x16_relaxed_swizzle(
387                i8x16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
388                i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1),
389            ),
390            &[i8x16(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1)],
391        );
392        compare_bytes(
393            i8x16_relaxed_swizzle(
394                i8x16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15),
395                u8x16(0x80, 0xff, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
396            ),
397            &[
398                i8x16(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
399                i8x16(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
400            ],
401        );
402        compare_bytes(
403            u8x16_relaxed_swizzle(
404                u8x16(
405                    128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
406                ),
407                u8x16(0x80, 0xff, 16, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
408            ),
409            &[
410                u8x16(
411                    128, 128, 128, 129, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
412                ),
413                u8x16(
414                    0, 0, 0, 0, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
415                ),
416            ],
417        );
418    }
419
420    #[test]
421    fn test_relaxed_trunc() {
422        compare_bytes(
423            i32x4_relaxed_trunc_f32x4(f32x4(1.0, 2.0, -1., -4.)),
424            &[i32x4(1, 2, -1, -4)],
425        );
426        compare_bytes(
427            i32x4_relaxed_trunc_f32x4(f32x4(f32::NEG_INFINITY, f32::NAN, -0.0, f32::INFINITY)),
428            &[
429                i32x4(i32::MIN, 0, 0, i32::MAX),
430                i32x4(i32::MIN, i32::MIN, 0, i32::MIN),
431            ],
432        );
433        compare_bytes(
434            i32x4_relaxed_trunc_f64x2_zero(f64x2(1.0, -3.0)),
435            &[i32x4(1, -3, 0, 0)],
436        );
437        compare_bytes(
438            i32x4_relaxed_trunc_f64x2_zero(f64x2(f64::INFINITY, f64::NAN)),
439            &[i32x4(i32::MAX, 0, 0, 0), i32x4(i32::MIN, i32::MIN, 0, 0)],
440        );
441
442        compare_bytes(
443            u32x4_relaxed_trunc_f32x4(f32x4(1.0, 2.0, 5., 100.)),
444            &[i32x4(1, 2, 5, 100)],
445        );
446        compare_bytes(
447            u32x4_relaxed_trunc_f32x4(f32x4(f32::NEG_INFINITY, f32::NAN, -0.0, f32::INFINITY)),
448            &[
449                u32x4(u32::MAX, 0, 0, u32::MAX),
450                u32x4(u32::MAX, u32::MAX, 0, u32::MAX),
451            ],
452        );
453        compare_bytes(
454            u32x4_relaxed_trunc_f64x2_zero(f64x2(1.0, 3.0)),
455            &[u32x4(1, 3, 0, 0)],
456        );
457        compare_bytes(
458            u32x4_relaxed_trunc_f64x2_zero(f64x2(f64::INFINITY, f64::NAN)),
459            &[i32x4(i32::MAX, 0, 0, 0), i32x4(i32::MIN, i32::MIN, 0, 0)],
460        );
461    }
462
463    #[test]
464    fn test_madd() {
465        let floats = [
466            f32::NAN,
467            f32::NEG_INFINITY,
468            f32::INFINITY,
469            1.0,
470            2.0,
471            -1.0,
472            0.0,
473            100.3,
474            7.8,
475            9.4,
476        ];
477        for &a in floats.iter() {
478            for &b in floats.iter() {
479                for &c in floats.iter() {
480                    let f1 = a * b + c;
481                    let f2 = a.mul_add(b, c);
482                    compare_bytes(
483                        f32x4_relaxed_madd(f32x4(a, a, a, a), f32x4(b, b, b, b), f32x4(c, c, c, c)),
484                        &[f32x4(f1, f1, f1, f1), f32x4(f2, f2, f2, f2)],
485                    );
486
487                    let f1 = -a * b + c;
488                    let f2 = (-a).mul_add(b, c);
489                    compare_bytes(
490                        f32x4_relaxed_nmadd(
491                            f32x4(a, a, a, a),
492                            f32x4(b, b, b, b),
493                            f32x4(c, c, c, c),
494                        ),
495                        &[f32x4(f1, f1, f1, f1), f32x4(f2, f2, f2, f2)],
496                    );
497
498                    let a = f64::from(a);
499                    let b = f64::from(b);
500                    let c = f64::from(c);
501                    let f1 = a * b + c;
502                    let f2 = a.mul_add(b, c);
503                    compare_bytes(
504                        f64x2_relaxed_madd(f64x2(a, a), f64x2(b, b), f64x2(c, c)),
505                        &[f64x2(f1, f1), f64x2(f2, f2)],
506                    );
507                    let f1 = -a * b + c;
508                    let f2 = (-a).mul_add(b, c);
509                    compare_bytes(
510                        f64x2_relaxed_nmadd(f64x2(a, a), f64x2(b, b), f64x2(c, c)),
511                        &[f64x2(f1, f1), f64x2(f2, f2)],
512                    );
513                }
514            }
515        }
516    }
517}