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