From 9be35f82c1abf2ecbab489bca9eca138ea648312 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Jul 2019 01:33:01 +0300 Subject: tests: Move run-pass tests without naming conflicts to ui --- src/test/ui/simd/simd-generics.rs | 39 +++++ src/test/ui/simd/simd-intrinsic-float-math.rs | 103 ++++++++++++ src/test/ui/simd/simd-intrinsic-float-minmax.rs | 54 ++++++ ...simd-intrinsic-generic-arithmetic-saturating.rs | 92 ++++++++++ .../ui/simd/simd-intrinsic-generic-arithmetic.rs | 120 +++++++++++++ src/test/ui/simd/simd-intrinsic-generic-bitmask.rs | 61 +++++++ src/test/ui/simd/simd-intrinsic-generic-cast.rs | 121 ++++++++++++++ .../ui/simd/simd-intrinsic-generic-comparison.rs | 106 ++++++++++++ .../ui/simd/simd-intrinsic-generic-elements.rs | 125 ++++++++++++++ src/test/ui/simd/simd-intrinsic-generic-gather.rs | 141 ++++++++++++++++ .../ui/simd/simd-intrinsic-generic-reduction.rs | 165 ++++++++++++++++++ src/test/ui/simd/simd-intrinsic-generic-select.rs | 173 +++++++++++++++++++ src/test/ui/simd/simd-size-align.rs | 96 +++++++++++ src/test/ui/simd/simd-target-feature-mixup.rs | 185 +++++++++++++++++++++ src/test/ui/simd/simd-type.rs | 16 ++ 15 files changed, 1597 insertions(+) create mode 100644 src/test/ui/simd/simd-generics.rs create mode 100644 src/test/ui/simd/simd-intrinsic-float-math.rs create mode 100644 src/test/ui/simd/simd-intrinsic-float-minmax.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-bitmask.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-cast.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-comparison.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-elements.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-gather.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-reduction.rs create mode 100644 src/test/ui/simd/simd-intrinsic-generic-select.rs create mode 100644 src/test/ui/simd/simd-size-align.rs create mode 100644 src/test/ui/simd/simd-target-feature-mixup.rs create mode 100644 src/test/ui/simd/simd-type.rs (limited to 'src/test/ui/simd') diff --git a/src/test/ui/simd/simd-generics.rs b/src/test/ui/simd/simd-generics.rs new file mode 100644 index 00000000000..ab6caee9d7b --- /dev/null +++ b/src/test/ui/simd/simd-generics.rs @@ -0,0 +1,39 @@ +// run-pass +#![allow(non_camel_case_types)] + + + +#![feature(repr_simd, platform_intrinsics)] + +use std::ops; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(f32, f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; +} + +fn add>(lhs: T, rhs: T) -> T { + lhs + rhs +} + +impl ops::Add for f32x4 { + type Output = f32x4; + + fn add(self, rhs: f32x4) -> f32x4 { + unsafe {simd_add(self, rhs)} + } +} + +pub fn main() { + let lr = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); + + // lame-o + let f32x4(x, y, z, w) = add(lr, lr); + assert_eq!(x, 2.0f32); + assert_eq!(y, 4.0f32); + assert_eq!(z, 6.0f32); + assert_eq!(w, 8.0f32); +} diff --git a/src/test/ui/simd/simd-intrinsic-float-math.rs b/src/test/ui/simd/simd-intrinsic-float-math.rs new file mode 100644 index 00000000000..220a59535ca --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-float-math.rs @@ -0,0 +1,103 @@ +// run-pass +// ignore-emscripten +// ignore-android + +// FIXME: this test fails on arm-android because the NDK version 14 is too old. +// It needs at least version 18. We disable it on all android build bots because +// there is no way in compile-test to disable it for an (arch,os) pair. + +// Test that the simd floating-point math intrinsics produce correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fsqrt(x: T) -> T; + fn simd_fabs(x: T) -> T; + fn simd_fsin(x: T) -> T; + fn simd_fcos(x: T) -> T; + fn simd_ceil(x: T) -> T; + fn simd_fexp(x: T) -> T; + fn simd_fexp2(x: T) -> T; + fn simd_floor(x: T) -> T; + fn simd_fma(x: T, y: T, z: T) -> T; + fn simd_flog(x: T) -> T; + fn simd_flog10(x: T) -> T; + fn simd_flog2(x: T) -> T; + fn simd_fpow(x: T, y: T) -> T; + fn simd_fpowi(x: T, y: i32) -> T; +} + +macro_rules! assert_approx_eq_f32 { + ($a:expr, $b:expr) => ({ + let (a, b) = (&$a, &$b); + assert!((*a - *b).abs() < 1.0e-6, + "{} is not approximately equal to {}", *a, *b); + }) +} +macro_rules! assert_approx_eq { + ($a:expr, $b:expr) => ({ + let a = $a; + let b = $b; + assert_approx_eq_f32!(a.0, b.0); + assert_approx_eq_f32!(a.1, b.1); + assert_approx_eq_f32!(a.2, b.2); + assert_approx_eq_f32!(a.3, b.3); + }) +} + +fn main() { + let x = f32x4(1.0, 1.0, 1.0, 1.0); + let y = f32x4(-1.0, -1.0, -1.0, -1.0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + let h = f32x4(0.5, 0.5, 0.5, 0.5); + + unsafe { + let r = simd_fabs(y); + assert_approx_eq!(x, r); + + let r = simd_fcos(z); + assert_approx_eq!(x, r); + + let r = simd_ceil(h); + assert_approx_eq!(x, r); + + let r = simd_fexp(z); + assert_approx_eq!(x, r); + + let r = simd_fexp2(z); + assert_approx_eq!(x, r); + + let r = simd_floor(h); + assert_approx_eq!(z, r); + + let r = simd_fma(x, h, h); + assert_approx_eq!(x, r); + + let r = simd_fsqrt(x); + assert_approx_eq!(x, r); + + let r = simd_flog(x); + assert_approx_eq!(z, r); + + let r = simd_flog2(x); + assert_approx_eq!(z, r); + + let r = simd_flog10(x); + assert_approx_eq!(z, r); + + let r = simd_fpow(h, x); + assert_approx_eq!(h, r); + + let r = simd_fpowi(h, 1); + assert_approx_eq!(h, r); + + let r = simd_fsin(z); + assert_approx_eq!(z, r); + } +} diff --git a/src/test/ui/simd/simd-intrinsic-float-minmax.rs b/src/test/ui/simd/simd-intrinsic-float-minmax.rs new file mode 100644 index 00000000000..350bc434935 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-float-minmax.rs @@ -0,0 +1,54 @@ +// run-pass +// ignore-emscripten +// min-llvm-version 7.0 +// error-pattern: panicked + +// Test that the simd_f{min,max} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_fmin(x: T, y: T) -> T; + fn simd_fmax(x: T, y: T) -> T; +} + +fn main() { + let x = f32x4(1.0, 2.0, 3.0, 4.0); + let y = f32x4(2.0, 1.0, 4.0, 3.0); + + #[cfg(not(any(target_arch = "mips", target_arch = "mips64")))] + let nan = ::std::f32::NAN; + // MIPS hardware treats f32::NAN as SNAN. Clear the signaling bit. + // See https://github.com/rust-lang/rust/issues/52746. + #[cfg(any(target_arch = "mips", target_arch = "mips64"))] + let nan = f32::from_bits(::std::f32::NAN.to_bits() - 1); + + let n = f32x4(nan, nan, nan, nan); + + unsafe { + let min0 = simd_fmin(x, y); + let min1 = simd_fmin(y, x); + assert_eq!(min0, min1); + let e = f32x4(1.0, 1.0, 3.0, 3.0); + assert_eq!(min0, e); + let minn = simd_fmin(x, n); + assert_eq!(minn, x); + let minn = simd_fmin(y, n); + assert_eq!(minn, y); + + let max0 = simd_fmax(x, y); + let max1 = simd_fmax(y, x); + assert_eq!(max0, max1); + let e = f32x4(2.0, 2.0, 4.0, 4.0); + assert_eq!(max0, e); + let maxn = simd_fmax(x, n); + assert_eq!(maxn, x); + let maxn = simd_fmax(y, n); + assert_eq!(maxn, y); + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs new file mode 100644 index 00000000000..b2ddcf023eb --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic-saturating.rs @@ -0,0 +1,92 @@ +// run-pass +// ignore-emscripten +// min-llvm-version 8.0 + +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +extern "platform-intrinsic" { + fn simd_saturating_add(x: T, y: T) -> T; + fn simd_saturating_sub(x: T, y: T) -> T; +} + +fn main() { + // unsigned + { + const M: u32 = u32::max_value(); + + let a = u32x4(1, 2, 3, 4); + let b = u32x4(2, 4, 6, 8); + let m = u32x4(M, M, M, M); + let m1 = u32x4(M - 1, M - 1, M - 1, M - 1); + let z = u32x4(0, 0, 0, 0); + + unsafe { + assert_eq!(simd_saturating_add(z, z), z); + assert_eq!(simd_saturating_add(z, a), a); + assert_eq!(simd_saturating_add(b, z), b); + assert_eq!(simd_saturating_add(a, a), b); + assert_eq!(simd_saturating_add(a, m), m); + assert_eq!(simd_saturating_add(m, b), m); + assert_eq!(simd_saturating_add(m1, a), m); + + assert_eq!(simd_saturating_sub(b, z), b); + assert_eq!(simd_saturating_sub(b, a), a); + assert_eq!(simd_saturating_sub(a, a), z); + assert_eq!(simd_saturating_sub(a, b), z); + assert_eq!(simd_saturating_sub(a, m1), z); + assert_eq!(simd_saturating_sub(b, m1), z); + } + } + + // signed + { + const MIN: i32 = i32::min_value(); + const MAX: i32 = i32::max_value(); + + let a = i32x4(1, 2, 3, 4); + let b = i32x4(2, 4, 6, 8); + let c = i32x4(-1, -2, -3, -4); + let d = i32x4(-2, -4, -6, -8); + + let max = i32x4(MAX, MAX, MAX, MAX); + let max1 = i32x4(MAX - 1, MAX - 1, MAX - 1, MAX - 1); + let min = i32x4(MIN, MIN, MIN, MIN); + let min1 = i32x4(MIN + 1, MIN + 1, MIN + 1, MIN + 1); + + let z = i32x4(0, 0, 0, 0); + + unsafe { + assert_eq!(simd_saturating_add(z, z), z); + assert_eq!(simd_saturating_add(z, a), a); + assert_eq!(simd_saturating_add(b, z), b); + assert_eq!(simd_saturating_add(a, a), b); + assert_eq!(simd_saturating_add(a, max), max); + assert_eq!(simd_saturating_add(max, b), max); + assert_eq!(simd_saturating_add(max1, a), max); + assert_eq!(simd_saturating_add(min1, z), min1); + assert_eq!(simd_saturating_add(min, z), min); + assert_eq!(simd_saturating_add(min1, c), min); + assert_eq!(simd_saturating_add(min, c), min); + assert_eq!(simd_saturating_add(min1, d), min); + assert_eq!(simd_saturating_add(min, d), min); + + assert_eq!(simd_saturating_sub(b, z), b); + assert_eq!(simd_saturating_sub(b, a), a); + assert_eq!(simd_saturating_sub(a, a), z); + assert_eq!(simd_saturating_sub(a, b), c); + assert_eq!(simd_saturating_sub(z, max), min1); + assert_eq!(simd_saturating_sub(min1, z), min1); + assert_eq!(simd_saturating_sub(min1, a), min); + assert_eq!(simd_saturating_sub(min1, b), min); + } + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs new file mode 100644 index 00000000000..b67c0ad1eb2 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-arithmetic.rs @@ -0,0 +1,120 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0 && a.1 == b.1 && a.2 == b.2 && a.3 == b.3); + }} +} + +extern "platform-intrinsic" { + fn simd_add(x: T, y: T) -> T; + fn simd_sub(x: T, y: T) -> T; + fn simd_mul(x: T, y: T) -> T; + fn simd_div(x: T, y: T) -> T; + fn simd_rem(x: T, y: T) -> T; + fn simd_shl(x: T, y: T) -> T; + fn simd_shr(x: T, y: T) -> T; + fn simd_and(x: T, y: T) -> T; + fn simd_or(x: T, y: T) -> T; + fn simd_xor(x: T, y: T) -> T; +} + +fn main() { + let x1 = i32x4(1, 2, 3, 4); + let y1 = u32x4(1, 2, 3, 4); + let z1 = f32x4(1.0, 2.0, 3.0, 4.0); + let x2 = i32x4(2, 3, 4, 5); + let y2 = u32x4(2, 3, 4, 5); + let z2 = f32x4(2.0, 3.0, 4.0, 5.0); + + unsafe { + all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(x2, x1), i32x4(3, 5, 7, 9)); + all_eq!(simd_add(y1, y2), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(y2, y1), u32x4(3, 5, 7, 9)); + all_eq!(simd_add(z1, z2), f32x4(3.0, 5.0, 7.0, 9.0)); + all_eq!(simd_add(z2, z1), f32x4(3.0, 5.0, 7.0, 9.0)); + + all_eq!(simd_mul(x1, x2), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(x2, x1), i32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y1, y2), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(y2, y1), u32x4(2, 6, 12, 20)); + all_eq!(simd_mul(z1, z2), f32x4(2.0, 6.0, 12.0, 20.0)); + all_eq!(simd_mul(z2, z1), f32x4(2.0, 6.0, 12.0, 20.0)); + + all_eq!(simd_sub(x2, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_sub(x1, x2), i32x4(-1, -1, -1, -1)); + all_eq!(simd_sub(y2, y1), u32x4(1, 1, 1, 1)); + all_eq!(simd_sub(y1, y2), u32x4(!0, !0, !0, !0)); + all_eq!(simd_sub(z2, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_sub(z1, z2), f32x4(-1.0, -1.0, -1.0, -1.0)); + + all_eq!(simd_div(x1, x1), i32x4(1, 1, 1, 1)); + all_eq!(simd_div(i32x4(2, 4, 6, 8), i32x4(2, 2, 2, 2)), x1); + all_eq!(simd_div(y1, y1), u32x4(1, 1, 1, 1)); + all_eq!(simd_div(u32x4(2, 4, 6, 8), u32x4(2, 2, 2, 2)), y1); + all_eq!(simd_div(z1, z1), f32x4(1.0, 1.0, 1.0, 1.0)); + all_eq!(simd_div(z1, z2), f32x4(1.0/2.0, 2.0/3.0, 3.0/4.0, 4.0/5.0)); + all_eq!(simd_div(z2, z1), f32x4(2.0/1.0, 3.0/2.0, 4.0/3.0, 5.0/4.0)); + + all_eq!(simd_rem(x1, x1), i32x4(0, 0, 0, 0)); + all_eq!(simd_rem(x2, x1), i32x4(0, 1, 1, 1)); + all_eq!(simd_rem(y1, y1), u32x4(0, 0, 0, 0)); + all_eq!(simd_rem(y2, y1), u32x4(0, 1, 1, 1)); + all_eq!(simd_rem(z1, z1), f32x4(0.0, 0.0, 0.0, 0.0)); + all_eq!(simd_rem(z1, z2), z1); + all_eq!(simd_rem(z2, z1), f32x4(0.0, 1.0, 1.0, 1.0)); + + all_eq!(simd_shl(x1, x2), i32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(x2, x1), i32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + all_eq!(simd_shl(y1, y2), u32x4(1 << 2, 2 << 3, 3 << 4, 4 << 5)); + all_eq!(simd_shl(y2, y1), u32x4(2 << 1, 3 << 2, 4 << 3, 5 << 4)); + + // test right-shift by assuming left-shift is correct + all_eq!(simd_shr(simd_shl(x1, x2), x2), x1); + all_eq!(simd_shr(simd_shl(x2, x1), x1), x2); + all_eq!(simd_shr(simd_shl(y1, y2), y2), y1); + all_eq!(simd_shr(simd_shl(y2, y1), y1), y2); + + // ensure we get logical vs. arithmetic shifts correct + let (a, b, c, d) = (-12, -123, -1234, -12345); + all_eq!(simd_shr(i32x4(a, b, c, d), x1), i32x4(a >> 1, b >> 2, c >> 3, d >> 4)); + all_eq!(simd_shr(u32x4(a as u32, b as u32, c as u32, d as u32), y1), + u32x4((a as u32) >> 1, (b as u32) >> 2, (c as u32) >> 3, (d as u32) >> 4)); + + all_eq!(simd_and(x1, x2), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(x2, x1), i32x4(0, 2, 0, 4)); + all_eq!(simd_and(y1, y2), u32x4(0, 2, 0, 4)); + all_eq!(simd_and(y2, y1), u32x4(0, 2, 0, 4)); + + all_eq!(simd_or(x1, x2), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(x2, x1), i32x4(3, 3, 7, 5)); + all_eq!(simd_or(y1, y2), u32x4(3, 3, 7, 5)); + all_eq!(simd_or(y2, y1), u32x4(3, 3, 7, 5)); + + all_eq!(simd_xor(x1, x2), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(x2, x1), i32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y1, y2), u32x4(3, 1, 7, 1)); + all_eq!(simd_xor(y2, y1), u32x4(3, 1, 7, 1)); + + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs new file mode 100644 index 00000000000..b28f742a92e --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-bitmask.rs @@ -0,0 +1,61 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten + +// Test that the simd_bitmask intrinsic produces correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u8x4(pub u8, pub u8, pub u8, pub u8); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct Tx4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_bitmask(x: T) -> U; +} + +fn main() { + let z = u32x4(0, 0, 0, 0); + let ez = 0_u8; + + let o = u32x4(!0, !0, !0, !0); + let eo = 0b_1111_u8; + + let m0 = u32x4(!0, 0, !0, 0); + let e0 = 0b_0000_0101_u8; + + // Check that the MSB is extracted: + let m = u8x4(0b_1000_0000, 0b_0100_0001, 0b_1100_0001, 0b_1111_1111); + let e = 0b_1101; + + // Check usize / isize + let msize: Tx4 = Tx4(usize::max_value(), 0, usize::max_value(), usize::max_value()); + + unsafe { + let r: u8 = simd_bitmask(z); + assert_eq!(r, ez); + + let r: u8 = simd_bitmask(o); + assert_eq!(r, eo); + + let r: u8 = simd_bitmask(m0); + assert_eq!(r, e0); + + let r: u8 = simd_bitmask(m); + assert_eq!(r, e); + + let r: u8 = simd_bitmask(msize); + assert_eq!(r, e); + + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-cast.rs b/src/test/ui/simd/simd-intrinsic-generic-cast.rs new file mode 100644 index 00000000000..15f232e2c0f --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-cast.rs @@ -0,0 +1,121 @@ +// run-pass +#![allow(unused_must_use)] +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics, concat_idents, test)] +#![allow(non_camel_case_types)] + +extern crate test; + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct i8x4(i8, i8, i8, i8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u32x4(u32, u32, u32, u32); +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct u8x4(u8, u8, u8, u8); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f32x4(f32, f32, f32, f32); + +#[repr(simd)] +#[derive(PartialEq, Debug)] +struct f64x4(f64, f64, f64, f64); + + +extern "platform-intrinsic" { + fn simd_cast(x: T) -> U; +} + +const A: i32 = -1234567; +const B: i32 = 12345678; +const C: i32 = -123456789; +const D: i32 = 1234567890; + +trait Foo { + fn is_float() -> bool { false } + fn in_range(x: i32) -> bool; +} +impl Foo for i32 { + fn in_range(_: i32) -> bool { true } +} +impl Foo for i8 { + fn in_range(x: i32) -> bool { -128 <= x && x < 128 } +} +impl Foo for u32 { + fn in_range(x: i32) -> bool { 0 <= x } +} +impl Foo for u8 { + fn in_range(x: i32) -> bool { 0 <= x && x < 128 } +} +impl Foo for f32 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} +impl Foo for f64 { + fn is_float() -> bool { true } + fn in_range(_: i32) -> bool { true } +} + +fn main() { + macro_rules! test { + ($from: ident, $to: ident) => {{ + // force the casts to actually happen, or else LLVM/rustc + // may fold them and get slightly different results. + let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); + // the SIMD vectors are all FOOx4, so we can concat_idents + // so we don't have to pass in the extra args to the macro + let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); + let mut to = concat_idents!($to, x4)(a as $to, + b as $to, + c as $to, + d as $to); + // assist type inference, it needs to know what `from` is + // for the `if` statements. + to == from; + + // there are platform differences for some out of range + // casts, so we just normalize such things: it's OK for + // "invalid" calculations to result in nonsense answers. + // (e.g., negative float to unsigned integer goes through a + // library routine on the default i686 platforms, and the + // implementation of that routine differs on e.g., Linux + // vs. macOS, resulting in different answers.) + if $from::is_float() { + if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } + if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } + if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } + if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } + } + + assert!(to == from, + "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), + from, to); + }} + } + macro_rules! tests { + (: $($to: ident),*) => { () }; + // repeating the list twice is easier than writing a cartesian + // product macro + ($from: ident $(, $from_: ident)*: $($to: ident),*) => { + fn $from() { unsafe { $( test!($from, $to); )* } } + tests!($($from_),*: $($to),*) + }; + ($($types: ident),*) => {{ + tests!($($types),* : $($types),*); + $($types();)* + }} + } + + // test various combinations, including truncation, + // signed/unsigned extension, and floating point casts. + tests!(i32, i8, u32, u8, f32); + tests!(i32, u32, f32, f64) +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs new file mode 100644 index 00000000000..2b593e1c9b8 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs @@ -0,0 +1,106 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics, concat_idents)] +#![allow(non_camel_case_types)] + +use std::f32::NAN; + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_eq(x: T, y: T) -> U; + fn simd_ne(x: T, y: T) -> U; + fn simd_lt(x: T, y: T) -> U; + fn simd_le(x: T, y: T) -> U; + fn simd_gt(x: T, y: T) -> U; + fn simd_ge(x: T, y: T) -> U; +} + +macro_rules! cmp { + ($method: ident($lhs: expr, $rhs: expr)) => {{ + let lhs = $lhs; + let rhs = $rhs; + let e: u32x4 = concat_idents!(simd_, $method)($lhs, $rhs); + // assume the scalar version is correct/the behaviour we want. + assert!((e.0 != 0) == lhs.0 .$method(&rhs.0)); + assert!((e.1 != 0) == lhs.1 .$method(&rhs.1)); + assert!((e.2 != 0) == lhs.2 .$method(&rhs.2)); + assert!((e.3 != 0) == lhs.3 .$method(&rhs.3)); + }} +} +macro_rules! tests { + ($($lhs: ident, $rhs: ident;)*) => {{ + $( + (|| { + cmp!(eq($lhs, $rhs)); + cmp!(ne($lhs, $rhs)); + + // test both directions + cmp!(lt($lhs, $rhs)); + cmp!(lt($rhs, $lhs)); + + cmp!(le($lhs, $rhs)); + cmp!(le($rhs, $lhs)); + + cmp!(gt($lhs, $rhs)); + cmp!(gt($rhs, $lhs)); + + cmp!(ge($lhs, $rhs)); + cmp!(ge($rhs, $lhs)); + })(); + )* + }} +} +fn main() { + // 13 vs. -100 tests that we get signed vs. unsigned comparisons + // correct (i32: 13 > -100, u32: 13 < -100). let i1 = i32x4(10, -11, 12, 13); + let i1 = i32x4(10, -11, 12, 13); + let i2 = i32x4(5, -5, 20, -100); + let i3 = i32x4(10, -11, 20, -100); + + let u1 = u32x4(10, !11+1, 12, 13); + let u2 = u32x4(5, !5+1, 20, !100+1); + let u3 = u32x4(10, !11+1, 20, !100+1); + + let f1 = f32x4(10.0, -11.0, 12.0, 13.0); + let f2 = f32x4(5.0, -5.0, 20.0, -100.0); + let f3 = f32x4(10.0, -11.0, 20.0, -100.0); + + unsafe { + tests! { + i1, i1; + u1, u1; + f1, f1; + + i1, i2; + u1, u2; + f1, f2; + + i1, i3; + u1, u3; + f1, f3; + } + } + + // NAN comparisons are special: + // -11 (*) 13 + // -5 -100 (*) + let f4 = f32x4(NAN, f1.1, NAN, f2.3); + + unsafe { + tests! { + f1, f4; + f2, f4; + f4, f4; + } + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-elements.rs b/src/test/ui/simd/simd-intrinsic-generic-elements.rs new file mode 100644 index 00000000000..ea3d4b18944 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-elements.rs @@ -0,0 +1,125 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x3(i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone, Debug, PartialEq)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, y: E) -> T; + fn simd_extract(x: T, idx: u32) -> E; + + fn simd_shuffle2(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle3(x: T, y: T, idx: [u32; 3]) -> U; + fn simd_shuffle4(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8(x: T, y: T, idx: [u32; 8]) -> U; +} + +macro_rules! all_eq { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + // type inference works better with the concrete type on the + // left, but humans work better with the expected on the + // right. + assert!(b == a, + "{:?} != {:?}", a, b); + }} +} + +fn main() { + let x2 = i32x2(20, 21); + let x3 = i32x3(30, 31, 32); + let x4 = i32x4(40, 41, 42, 43); + let x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); + unsafe { + all_eq!(simd_insert(x2, 0, 100), i32x2(100, 21)); + all_eq!(simd_insert(x2, 1, 100), i32x2(20, 100)); + + all_eq!(simd_insert(x3, 0, 100), i32x3(100, 31, 32)); + all_eq!(simd_insert(x3, 1, 100), i32x3(30, 100, 32)); + all_eq!(simd_insert(x3, 2, 100), i32x3(30, 31, 100)); + + all_eq!(simd_insert(x4, 0, 100), i32x4(100, 41, 42, 43)); + all_eq!(simd_insert(x4, 1, 100), i32x4(40, 100, 42, 43)); + all_eq!(simd_insert(x4, 2, 100), i32x4(40, 41, 100, 43)); + all_eq!(simd_insert(x4, 3, 100), i32x4(40, 41, 42, 100)); + + all_eq!(simd_insert(x8, 0, 100), i32x8(100, 81, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 1, 100), i32x8(80, 100, 82, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 2, 100), i32x8(80, 81, 100, 83, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 3, 100), i32x8(80, 81, 82, 100, 84, 85, 86, 87)); + all_eq!(simd_insert(x8, 4, 100), i32x8(80, 81, 82, 83, 100, 85, 86, 87)); + all_eq!(simd_insert(x8, 5, 100), i32x8(80, 81, 82, 83, 84, 100, 86, 87)); + all_eq!(simd_insert(x8, 6, 100), i32x8(80, 81, 82, 83, 84, 85, 100, 87)); + all_eq!(simd_insert(x8, 7, 100), i32x8(80, 81, 82, 83, 84, 85, 86, 100)); + + all_eq!(simd_extract(x2, 0), 20); + all_eq!(simd_extract(x2, 1), 21); + + all_eq!(simd_extract(x3, 0), 30); + all_eq!(simd_extract(x3, 1), 31); + all_eq!(simd_extract(x3, 2), 32); + + all_eq!(simd_extract(x4, 0), 40); + all_eq!(simd_extract(x4, 1), 41); + all_eq!(simd_extract(x4, 2), 42); + all_eq!(simd_extract(x4, 3), 43); + + all_eq!(simd_extract(x8, 0), 80); + all_eq!(simd_extract(x8, 1), 81); + all_eq!(simd_extract(x8, 2), 82); + all_eq!(simd_extract(x8, 3), 83); + all_eq!(simd_extract(x8, 4), 84); + all_eq!(simd_extract(x8, 5), 85); + all_eq!(simd_extract(x8, 6), 86); + all_eq!(simd_extract(x8, 7), 87); + } + + let y2 = i32x2(120, 121); + let y3 = i32x3(130, 131, 132); + let y4 = i32x4(140, 141, 142, 143); + let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + unsafe { + all_eq!(simd_shuffle2(x2, y2, [3, 0]), i32x2(121, 20)); + all_eq!(simd_shuffle3(x2, y2, [3, 0, 1]), i32x3(121, 20, 21)); + all_eq!(simd_shuffle4(x2, y2, [3, 0, 1, 2]), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle8(x2, y2, [3, 0, 1, 2, 1, 2, 3, 0]), + i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + + all_eq!(simd_shuffle2(x3, y3, [4, 2]), i32x2(131, 32)); + all_eq!(simd_shuffle3(x3, y3, [4, 2, 3]), i32x3(131, 32, 130)); + all_eq!(simd_shuffle4(x3, y3, [4, 2, 3, 0]), i32x4(131, 32, 130, 30)); + all_eq!(simd_shuffle8(x3, y3, [4, 2, 3, 0, 1, 5, 5, 1]), + i32x8(131, 32, 130, 30, 31, 132, 132, 31)); + + all_eq!(simd_shuffle2(x4, y4, [7, 2]), i32x2(143, 42)); + all_eq!(simd_shuffle3(x4, y4, [7, 2, 5]), i32x3(143, 42, 141)); + all_eq!(simd_shuffle4(x4, y4, [7, 2, 5, 0]), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle8(x4, y4, [7, 2, 5, 0, 3, 6, 4, 1]), + i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + + all_eq!(simd_shuffle2(x8, y8, [11, 5]), i32x2(183, 85)); + all_eq!(simd_shuffle3(x8, y8, [11, 5, 15]), i32x3(183, 85, 187)); + all_eq!(simd_shuffle4(x8, y8, [11, 5, 15, 0]), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle8(x8, y8, [11, 5, 15, 0, 3, 8, 12, 1]), + i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + } + +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-gather.rs b/src/test/ui/simd/simd-intrinsic-generic-gather.rs new file mode 100644 index 00000000000..805caebe5b1 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-gather.rs @@ -0,0 +1,141 @@ +// run-pass +// ignore-emscripten + +// Test that the simd_{gather,scatter} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather(x: T, y: U, z: V) -> T; + fn simd_scatter(x: T, y: U, z: V) -> (); +} + +fn main() { + let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; + + let default = x4(-3_f32, -3., -3., -3.); + let s_strided = x4(0_f32, 2., -3., 6.); + let mask = x4(-1_i32, -1, 0, -1); + + // reading from *const + unsafe { + let pointer = &x[0] as *const f32; + let pointers = x4( + pointer.offset(0) as *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = &mut x[0] as *mut f32; + let pointers = x4( + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let values = x4(42_f32, 43_f32, 44_f32, 45_f32); + simd_scatter(values, pointers, mask); + + assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); + } + + // test modifying array of *const f32 + let mut y = [ + &x[0] as *const f32, + &x[1] as *const f32, + &x[2] as *const f32, + &x[3] as *const f32, + &x[4] as *const f32, + &x[5] as *const f32, + &x[6] as *const f32, + &x[7] as *const f32 + ]; + + let default = x4(y[0], y[0], y[0], y[0]); + let s_strided = x4(y[0], y[2], y[0], y[6]); + + // reading from *const + unsafe { + let pointer = &y[0] as *const *const f32; + let pointers = x4( + pointer.offset(0) as *const *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // reading from *mut + unsafe { + let pointer = &mut y[0] as *mut *const f32; + let pointers = x4( + pointer.offset(0) as *mut *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let r_strided = simd_gather(default, pointers, mask); + + assert_eq!(r_strided, s_strided); + } + + // writing to *mut + unsafe { + let pointer = &mut y[0] as *mut *const f32; + let pointers = x4( + pointer.offset(0) as *mut *const f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ); + + let values = x4(y[7], y[6], y[5], y[1]); + simd_scatter(values, pointers, mask); + + let s = [ + &x[7] as *const f32, + &x[1] as *const f32, + &x[6] as *const f32, + &x[3] as *const f32, + &x[4] as *const f32, + &x[5] as *const f32, + &x[1] as *const f32, + &x[7] as *const f32 + ]; + assert_eq!(y, s); + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-reduction.rs b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs new file mode 100644 index 00000000000..4195444a73f --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-reduction.rs @@ -0,0 +1,165 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// min-system-llvm-version: 9.0 + +// Test that the simd_reduce_{op} intrinsics produce the correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct b8x16( + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8, + pub i8, pub i8, pub i8, pub i8 +); + +extern "platform-intrinsic" { + fn simd_reduce_add_unordered(x: T) -> U; + fn simd_reduce_mul_unordered(x: T) -> U; + fn simd_reduce_add_ordered(x: T, acc: U) -> U; + fn simd_reduce_mul_ordered(x: T, acc: U) -> U; + fn simd_reduce_min(x: T) -> U; + fn simd_reduce_max(x: T) -> U; + fn simd_reduce_min_nanless(x: T) -> U; + fn simd_reduce_max_nanless(x: T) -> U; + fn simd_reduce_and(x: T) -> U; + fn simd_reduce_or(x: T) -> U; + fn simd_reduce_xor(x: T) -> U; + fn simd_reduce_all(x: T) -> bool; + fn simd_reduce_any(x: T) -> bool; +} + +fn main() { + unsafe { + let x = i32x4(1, -2, 3, 4); + let r: i32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_i32); + let r: i32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_i32); + let r: i32 = simd_reduce_add_ordered(x, -1); + assert_eq!(r, 5_i32); + let r: i32 = simd_reduce_mul_ordered(x, -1); + assert_eq!(r, 24_i32); + + let r: i32 = simd_reduce_min(x); + assert_eq!(r, -2_i32); + let r: i32 = simd_reduce_max(x); + assert_eq!(r, 4_i32); + + let x = i32x4(-1, -1, -1, -1); + let r: i32 = simd_reduce_and(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_or(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_xor(x); + assert_eq!(r, 0_i32); + + let x = i32x4(-1, -1, 0, -1); + let r: i32 = simd_reduce_and(x); + assert_eq!(r, 0_i32); + let r: i32 = simd_reduce_or(x); + assert_eq!(r, -1_i32); + let r: i32 = simd_reduce_xor(x); + assert_eq!(r, -1_i32); + } + + unsafe { + let x = u32x4(1, 2, 3, 4); + let r: u32 = simd_reduce_add_unordered(x); + assert_eq!(r, 10_u32); + let r: u32 = simd_reduce_mul_unordered(x); + assert_eq!(r, 24_u32); + let r: u32 = simd_reduce_add_ordered(x, 1); + assert_eq!(r, 11_u32); + let r: u32 = simd_reduce_mul_ordered(x, 2); + assert_eq!(r, 48_u32); + + let r: u32 = simd_reduce_min(x); + assert_eq!(r, 1_u32); + let r: u32 = simd_reduce_max(x); + assert_eq!(r, 4_u32); + + let t = u32::max_value(); + let x = u32x4(t, t, t, t); + let r: u32 = simd_reduce_and(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_or(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_xor(x); + assert_eq!(r, 0_u32); + + let x = u32x4(t, t, 0, t); + let r: u32 = simd_reduce_and(x); + assert_eq!(r, 0_u32); + let r: u32 = simd_reduce_or(x); + assert_eq!(r, t); + let r: u32 = simd_reduce_xor(x); + assert_eq!(r, t); + } + + unsafe { + let x = f32x4(1., -2., 3., 4.); + let r: f32 = simd_reduce_add_unordered(x); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_unordered(x); + assert_eq!(r, -24_f32); + let r: f32 = simd_reduce_add_ordered(x, 0.); + assert_eq!(r, 6_f32); + let r: f32 = simd_reduce_mul_ordered(x, 1.); + assert_eq!(r, -24_f32); + let r: f32 = simd_reduce_add_ordered(x, 1.); + assert_eq!(r, 7_f32); + let r: f32 = simd_reduce_mul_ordered(x, 2.); + assert_eq!(r, -48_f32); + + let r: f32 = simd_reduce_min(x); + assert_eq!(r, -2_f32); + let r: f32 = simd_reduce_max(x); + assert_eq!(r, 4_f32); + let r: f32 = simd_reduce_min_nanless(x); + assert_eq!(r, -2_f32); + let r: f32 = simd_reduce_max_nanless(x); + assert_eq!(r, 4_f32); + } + + unsafe { + let x = b8x4(!0, !0, !0, !0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, true); + let r: bool = simd_reduce_any(x); + assert_eq!(r, true); + + let x = b8x4(!0, !0, 0, !0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, false); + let r: bool = simd_reduce_any(x); + assert_eq!(r, true); + + let x = b8x4(0, 0, 0, 0); + let r: bool = simd_reduce_all(x); + assert_eq!(r, false); + let r: bool = simd_reduce_any(x); + assert_eq!(r, false); + } +} diff --git a/src/test/ui/simd/simd-intrinsic-generic-select.rs b/src/test/ui/simd/simd-intrinsic-generic-select.rs new file mode 100644 index 00000000000..22bda4fc9d9 --- /dev/null +++ b/src/test/ui/simd/simd-intrinsic-generic-select.rs @@ -0,0 +1,173 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// ignore-mips behavior of simd_select_bitmask is endian-specific +// ignore-mips64 behavior of simd_select_bitmask is endian-specific +// ignore-powerpc behavior of simd_select_bitmask is endian-specific +// ignore-powerpc64 behavior of simd_select_bitmask is endian-specific + +// Test that the simd_select intrinsics produces correct results. + +#![feature(repr_simd, platform_intrinsics)] +#[allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct u32x8(u32, u32, u32, u32, u32, u32, u32, u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_select(x: T, a: U, b: U) -> U; + fn simd_select_bitmask(x: T, a: U, b: U) -> U; +} + +fn main() { + let m0 = b8x4(!0, !0, !0, !0); + let m1 = b8x4(0, 0, 0, 0); + let m2 = b8x4(!0, !0, 0, 0); + let m3 = b8x4(0, 0, !0, !0); + let m4 = b8x4(!0, 0, !0, 0); + + unsafe { + let a = i32x4(1, -2, 3, 4); + let b = i32x4(5, 6, -7, 8); + + let r: i32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: i32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: i32x4 = simd_select(m2, a, b); + let e = i32x4(1, -2, -7, 8); + assert_eq!(r, e); + + let r: i32x4 = simd_select(m3, a, b); + let e = i32x4(5, 6, 3, 4); + assert_eq!(r, e); + + let r: i32x4 = simd_select(m4, a, b); + let e = i32x4(1, 6, 3, 8); + assert_eq!(r, e); + } + + unsafe { + let a = u32x4(1, 2, 3, 4); + let b = u32x4(5, 6, 7, 8); + + let r: u32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x4 = simd_select(m2, a, b); + let e = u32x4(1, 2, 7, 8); + assert_eq!(r, e); + + let r: u32x4 = simd_select(m3, a, b); + let e = u32x4(5, 6, 3, 4); + assert_eq!(r, e); + + let r: u32x4 = simd_select(m4, a, b); + let e = u32x4(1, 6, 3, 8); + assert_eq!(r, e); + } + + unsafe { + let a = f32x4(1., 2., 3., 4.); + let b = f32x4(5., 6., 7., 8.); + + let r: f32x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: f32x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: f32x4 = simd_select(m2, a, b); + let e = f32x4(1., 2., 7., 8.); + assert_eq!(r, e); + + let r: f32x4 = simd_select(m3, a, b); + let e = f32x4(5., 6., 3., 4.); + assert_eq!(r, e); + + let r: f32x4 = simd_select(m4, a, b); + let e = f32x4(1., 6., 3., 8.); + assert_eq!(r, e); + } + + unsafe { + let t = !0 as i8; + let f = 0 as i8; + let a = b8x4(t, f, t, f); + let b = b8x4(f, f, f, t); + + let r: b8x4 = simd_select(m0, a, b); + let e = a; + assert_eq!(r, e); + + let r: b8x4 = simd_select(m1, a, b); + let e = b; + assert_eq!(r, e); + + let r: b8x4 = simd_select(m2, a, b); + let e = b8x4(t, f, f, t); + assert_eq!(r, e); + + let r: b8x4 = simd_select(m3, a, b); + let e = b8x4(f, f, t, f); + assert_eq!(r, e); + + let r: b8x4 = simd_select(m4, a, b); + let e = b8x4(t, f, t, t); + assert_eq!(r, e); + } + + unsafe { + let a = u32x8(0, 1, 2, 3, 4, 5, 6, 7); + let b = u32x8(8, 9, 10, 11, 12, 13, 14, 15); + + let r: u32x8 = simd_select_bitmask(0u8, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0xffu8, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b01010101u8, a, b); + let e = u32x8(0, 9, 2, 11, 4, 13, 6, 15); + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b10101010u8, a, b); + let e = u32x8(8, 1, 10, 3, 12, 5, 14, 7); + assert_eq!(r, e); + + let r: u32x8 = simd_select_bitmask(0b11110000u8, a, b); + let e = u32x8(8, 9, 10, 11, 4, 5, 6, 7); + assert_eq!(r, e); + } +} diff --git a/src/test/ui/simd/simd-size-align.rs b/src/test/ui/simd/simd-size-align.rs new file mode 100644 index 00000000000..556013788c3 --- /dev/null +++ b/src/test/ui/simd/simd-size-align.rs @@ -0,0 +1,96 @@ +// run-pass +#![allow(deprecated)] + + +#![feature(repr_simd)] +#![allow(non_camel_case_types)] + +use std::mem; + +/// `T` should satisfy `size_of T (mod min_align_of T) === 0` to be stored at `Vec` properly +/// Please consult the issue #20460 +fn check() { + assert_eq!(mem::size_of::() % mem::min_align_of::(), 0) +} + +fn main() { + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); + check::(); +} + +#[repr(simd)] struct u8x2(u8, u8); +#[repr(simd)] struct u8x3(u8, u8, u8); +#[repr(simd)] struct u8x4(u8, u8, u8, u8); +#[repr(simd)] struct u8x5(u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x6(u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x7(u8, u8, u8, u8, u8, u8, u8); +#[repr(simd)] struct u8x8(u8, u8, u8, u8, u8, u8, u8, u8); + +#[repr(simd)] struct i16x2(i16, i16); +#[repr(simd)] struct i16x3(i16, i16, i16); +#[repr(simd)] struct i16x4(i16, i16, i16, i16); +#[repr(simd)] struct i16x5(i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x6(i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x7(i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); + +#[repr(simd)] struct f32x2(f32, f32); +#[repr(simd)] struct f32x3(f32, f32, f32); +#[repr(simd)] struct f32x4(f32, f32, f32, f32); +#[repr(simd)] struct f32x5(f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x6(f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x7(f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); + +#[repr(simd)] struct usizex2(usize, usize); +#[repr(simd)] struct usizex3(usize, usize, usize); +#[repr(simd)] struct usizex4(usize, usize, usize, usize); +#[repr(simd)] struct usizex5(usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex6(usize, usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex7(usize, usize, usize, usize, usize, usize, usize); +#[repr(simd)] struct usizex8(usize, usize, usize, usize, usize, usize, usize, usize); + +#[repr(simd)] struct isizex2(isize, isize); +#[repr(simd)] struct isizex3(isize, isize, isize); +#[repr(simd)] struct isizex4(isize, isize, isize, isize); +#[repr(simd)] struct isizex5(isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex6(isize, isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex7(isize, isize, isize, isize, isize, isize, isize); +#[repr(simd)] struct isizex8(isize, isize, isize, isize, isize, isize, isize, isize); diff --git a/src/test/ui/simd/simd-target-feature-mixup.rs b/src/test/ui/simd/simd-target-feature-mixup.rs new file mode 100644 index 00000000000..6d7688191b7 --- /dev/null +++ b/src/test/ui/simd/simd-target-feature-mixup.rs @@ -0,0 +1,185 @@ +// run-pass +#![allow(unused_variables)] +#![allow(stable_features)] +#![allow(overflowing_literals)] + +// ignore-emscripten +// ignore-sgx no processes + +#![feature(repr_simd, target_feature, cfg_target_feature)] +#![feature(avx512_target_feature)] + +use std::process::{Command, ExitStatus}; +use std::env; + +fn main() { + if let Some(level) = env::args().nth(1) { + return test::main(&level) + } + + let me = env::current_exe().unwrap(); + for level in ["sse", "avx", "avx512"].iter() { + let status = Command::new(&me).arg(level).status().unwrap(); + if status.success() { + println!("success with {}", level); + continue + } + + // We don't actually know if our computer has the requisite target features + // for the test below. Testing for that will get added to libstd later so + // for now just assume sigill means this is a machine that can't run this test. + if is_sigill(status) { + println!("sigill with {}, assuming spurious", level); + continue + } + panic!("invalid status at {}: {}", level, status); + } +} + +#[cfg(unix)] +fn is_sigill(status: ExitStatus) -> bool { + use std::os::unix::prelude::*; + status.signal() == Some(4) +} + +#[cfg(windows)] +fn is_sigill(status: ExitStatus) -> bool { + status.code() == Some(0xc000001d) +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[allow(nonstandard_style)] +mod test { + // An SSE type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m128i(u64, u64); + + // An AVX type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m256i(u64, u64, u64, u64); + + // An AVX-512 type + #[repr(simd)] + #[derive(PartialEq, Debug, Clone, Copy)] + struct __m512i(u64, u64, u64, u64, u64, u64, u64, u64); + + pub fn main(level: &str) { + unsafe { + main_normal(level); + main_sse(level); + if level == "sse" { + return + } + main_avx(level); + if level == "avx" { + return + } + main_avx512(level); + } + } + + macro_rules! mains { + ($( + $(#[$attr:meta])* + unsafe fn $main:ident(level: &str) { + ... + } + )*) => ($( + $(#[$attr])* + unsafe fn $main(level: &str) { + let m128 = __m128i(1, 2); + let m256 = __m256i(3, 4, 5, 6); + let m512 = __m512i(7, 8, 9, 10, 11, 12, 13, 14); + assert_eq!(id_sse_128(m128), m128); + assert_eq!(id_sse_256(m256), m256); + assert_eq!(id_sse_512(m512), m512); + + if level == "sse" { + return + } + assert_eq!(id_avx_128(m128), m128); + assert_eq!(id_avx_256(m256), m256); + assert_eq!(id_avx_512(m512), m512); + + if level == "avx" { + return + } + assert_eq!(id_avx512_128(m128), m128); + assert_eq!(id_avx512_256(m256), m256); + assert_eq!(id_avx512_512(m512), m512); + } + )*) + } + + mains! { + unsafe fn main_normal(level: &str) { ... } + #[target_feature(enable = "sse2")] + unsafe fn main_sse(level: &str) { ... } + #[target_feature(enable = "avx")] + unsafe fn main_avx(level: &str) { ... } + #[target_feature(enable = "avx512bw")] + unsafe fn main_avx512(level: &str) { ... } + } + + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "sse2")] + unsafe fn id_sse_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx")] + unsafe fn id_avx_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_128(a: __m128i) -> __m128i { + assert_eq!(a, __m128i(1, 2)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_256(a: __m256i) -> __m256i { + assert_eq!(a, __m256i(3, 4, 5, 6)); + a.clone() + } + + #[target_feature(enable = "avx512bw")] + unsafe fn id_avx512_512(a: __m512i) -> __m512i { + assert_eq!(a, __m512i(7, 8, 9, 10, 11, 12, 13, 14)); + a.clone() + } +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +mod test { + pub fn main(level: &str) {} +} diff --git a/src/test/ui/simd/simd-type.rs b/src/test/ui/simd/simd-type.rs new file mode 100644 index 00000000000..e7b9bfe32f8 --- /dev/null +++ b/src/test/ui/simd/simd-type.rs @@ -0,0 +1,16 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd)] + +#[repr(simd)] +struct RGBA { + r: f32, + g: f32, + b: f32, + a: f32 +} + +pub fn main() {} -- cgit 1.4.1-3-g733a5