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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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#[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}