diff options
Diffstat (limited to 'src/test/ui/simd')
73 files changed, 3715 insertions, 0 deletions
diff --git a/src/test/ui/simd/array-trait.rs b/src/test/ui/simd/array-trait.rs new file mode 100644 index 000000000..45c10b378 --- /dev/null +++ b/src/test/ui/simd/array-trait.rs @@ -0,0 +1,41 @@ +// Figuring out the size of a vector type that depends on traits doesn't ICE + +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics, generic_const_exprs)] +#![allow(non_camel_case_types, incomplete_features)] + +pub trait Simd { + type Lane: Clone + Copy; + const SIZE: usize; +} + +pub struct i32x4; +impl Simd for i32x4 { + type Lane = i32; + const SIZE: usize = 4; +} + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct T<S: Simd>([S::Lane; S::SIZE]); +//~^ ERROR unconstrained generic constant + +extern "platform-intrinsic" { + fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut t = T::<i32x4>([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/array-trait.stderr b/src/test/ui/simd/array-trait.stderr new file mode 100644 index 000000000..765215c39 --- /dev/null +++ b/src/test/ui/simd/array-trait.stderr @@ -0,0 +1,10 @@ +error: unconstrained generic constant + --> $DIR/array-trait.rs:23:23 + | +LL | pub struct T<S: Simd>([S::Lane; S::SIZE]); + | ^^^^^^^^^^^^^^^^^^ + | + = help: try adding a `where` bound using this expression: `where [(); S::SIZE]:` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/array-type.rs b/src/test/ui/simd/array-type.rs new file mode 100644 index 000000000..7d66395a3 --- /dev/null +++ b/src/test/ui/simd/array-type.rs @@ -0,0 +1,42 @@ +// run-pass +#![allow(dead_code)] + +// pretty-expanded FIXME #23616 + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +struct S([i32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct T<const N: usize>([i32; N]); + +extern "platform-intrinsic" { + fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; +} + +pub fn main() { + let mut s = S([0; 4]); + + unsafe { + for i in 0_i32..4 { + s = simd_insert(s, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(s, i as u32)); + } + } + + let mut t = T::<4>([0; 4]); + unsafe { + for i in 0_i32..4 { + t = simd_insert(t, i as u32, i); + } + for i in 0_i32..4 { + assert_eq!(i, simd_extract(t, i as u32)); + } + } +} diff --git a/src/test/ui/simd/generics.rs b/src/test/ui/simd/generics.rs new file mode 100644 index 000000000..fa9d35ee4 --- /dev/null +++ b/src/test/ui/simd/generics.rs @@ -0,0 +1,85 @@ +// 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); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct A<const N: usize>([f32; N]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct B<T>([T; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct C<T, const N: usize>([T; N]); + + +extern "platform-intrinsic" { + fn simd_add<T>(x: T, y: T) -> T; +} + +fn add<T: ops::Add<Output=T>>(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) } + } +} + +impl ops::Add for A<4> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + +impl ops::Add for B<f32> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + +impl ops::Add for C<f32, 4> { + type Output = Self; + + fn add(self, rhs: Self) -> Self { + unsafe { simd_add(self, rhs) } + } +} + + +pub fn main() { + let x = [1.0f32, 2.0f32, 3.0f32, 4.0f32]; + let y = [2.0f32, 4.0f32, 6.0f32, 8.0f32]; + + // lame-o + let a = f32x4(1.0f32, 2.0f32, 3.0f32, 4.0f32); + let f32x4(a0, a1, a2, a3) = add(a, a); + assert_eq!(a0, 2.0f32); + assert_eq!(a1, 4.0f32); + assert_eq!(a2, 6.0f32); + assert_eq!(a3, 8.0f32); + + let a = A(x); + assert_eq!(add(a, a).0, y); + + let b = B(x); + assert_eq!(add(b, b).0, y); + + let c = C(x); + assert_eq!(add(c, c).0, y); +} diff --git a/src/test/ui/simd/intrinsic/float-math-pass.rs b/src/test/ui/simd/intrinsic/float-math-pass.rs new file mode 100644 index 000000000..7a4f74665 --- /dev/null +++ b/src/test/ui/simd/intrinsic/float-math-pass.rs @@ -0,0 +1,114 @@ +// 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<T>(x: T) -> T; + fn simd_fabs<T>(x: T) -> T; + fn simd_fsin<T>(x: T) -> T; + fn simd_fcos<T>(x: T) -> T; + fn simd_fexp<T>(x: T) -> T; + fn simd_fexp2<T>(x: T) -> T; + fn simd_fma<T>(x: T, y: T, z: T) -> T; + fn simd_flog<T>(x: T) -> T; + fn simd_flog10<T>(x: T) -> T; + fn simd_flog2<T>(x: T) -> T; + fn simd_fpow<T>(x: T, y: T) -> T; + fn simd_fpowi<T>(x: T, y: i32) -> T; + + // rounding functions + fn simd_ceil<T>(x: T) -> T; + fn simd_floor<T>(x: T) -> T; + fn simd_round<T>(x: T) -> T; + fn simd_trunc<T>(x: T) -> 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_fexp(z); + assert_approx_eq!(x, r); + + let r = simd_fexp2(z); + assert_approx_eq!(x, 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); + + // rounding functions + let r = simd_floor(h); + assert_eq!(z, r); + + let r = simd_ceil(h); + assert_eq!(x, r); + + let r = simd_round(h); + assert_eq!(x, r); + + let r = simd_trunc(h); + assert_eq!(z, r); + } +} diff --git a/src/test/ui/simd/intrinsic/float-minmax-pass.rs b/src/test/ui/simd/intrinsic/float-minmax-pass.rs new file mode 100644 index 000000000..d79be61f9 --- /dev/null +++ b/src/test/ui/simd/intrinsic/float-minmax-pass.rs @@ -0,0 +1,52 @@ +// run-pass +// ignore-emscripten + +// 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<T>(x: T, y: T) -> T; + fn simd_fmax<T>(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 = 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(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/intrinsic/generic-arithmetic-2.rs b/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs new file mode 100644 index 000000000..3576eed71 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-2.rs @@ -0,0 +1,103 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_add<T>(x: T, y: T) -> T; + fn simd_sub<T>(x: T, y: T) -> T; + fn simd_mul<T>(x: T, y: T) -> T; + fn simd_div<T>(x: T, y: T) -> T; + fn simd_rem<T>(x: T, y: T) -> T; + fn simd_shl<T>(x: T, y: T) -> T; + fn simd_shr<T>(x: T, y: T) -> T; + fn simd_and<T>(x: T, y: T) -> T; + fn simd_or<T>(x: T, y: T) -> T; + fn simd_xor<T>(x: T, y: T) -> T; + + fn simd_neg<T>(x: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_add(x, x); + simd_add(y, y); + simd_add(z, z); + simd_sub(x, x); + simd_sub(y, y); + simd_sub(z, z); + simd_mul(x, x); + simd_mul(y, y); + simd_mul(z, z); + simd_div(x, x); + simd_div(y, y); + simd_div(z, z); + simd_rem(x, x); + simd_rem(y, y); + simd_rem(z, z); + + simd_shl(x, x); + simd_shl(y, y); + simd_shr(x, x); + simd_shr(y, y); + simd_and(x, x); + simd_and(y, y); + simd_or(x, x); + simd_or(y, y); + simd_xor(x, x); + simd_xor(y, y); + + simd_neg(x); + simd_neg(z); + + + simd_add(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_sub(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_mul(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_div(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shl(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_shr(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_and(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_or(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_xor(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_neg(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + + simd_shl(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_shr(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_and(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_or(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + simd_xor(z, z); +//~^ ERROR unsupported operation on `f32x4` with element `f32` + } +} diff --git a/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr b/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr new file mode 100644 index 000000000..0f0a7ea66 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-2.stderr @@ -0,0 +1,93 @@ +error[E0511]: invalid monomorphization of `simd_add` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:69:9 + | +LL | simd_add(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_sub` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:71:9 + | +LL | simd_sub(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_mul` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:73:9 + | +LL | simd_mul(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_div` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:75:9 + | +LL | simd_div(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shl` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:77:9 + | +LL | simd_shl(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shr` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:79:9 + | +LL | simd_shr(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_and` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:81:9 + | +LL | simd_and(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_or` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:83:9 + | +LL | simd_or(0, 0); + | ^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_xor` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:85:9 + | +LL | simd_xor(0, 0); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_neg` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-arithmetic-2.rs:88:9 + | +LL | simd_neg(0); + | ^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:92:9 + | +LL | simd_shl(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:94:9 + | +LL | simd_shr(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:96:9 + | +LL | simd_and(z, z); + | ^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:98:9 + | +LL | simd_or(z, z); + | ^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32` + --> $DIR/generic-arithmetic-2.rs:100:9 + | +LL | simd_xor(z, z); + | ^^^^^^^^^^^^^^ + +error: aborting due to 15 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs b/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs new file mode 100644 index 000000000..c507b8d31 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-pass.rs @@ -0,0 +1,136 @@ +// 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 U32<const N: usize>([u32; N]); + +#[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); + }} +} + +macro_rules! all_eq_ { + ($a: expr, $b: expr) => {{ + let a = $a; + let b = $b; + assert!(a.0 == b.0); + }} +} + + +extern "platform-intrinsic" { + fn simd_add<T>(x: T, y: T) -> T; + fn simd_sub<T>(x: T, y: T) -> T; + fn simd_mul<T>(x: T, y: T) -> T; + fn simd_div<T>(x: T, y: T) -> T; + fn simd_rem<T>(x: T, y: T) -> T; + fn simd_shl<T>(x: T, y: T) -> T; + fn simd_shr<T>(x: T, y: T) -> T; + fn simd_and<T>(x: T, y: T) -> T; + fn simd_or<T>(x: T, y: T) -> T; + fn simd_xor<T>(x: T, y: T) -> T; + + fn simd_neg<T>(x: T) -> T; +} + +fn main() { + let x1 = i32x4(1, 2, 3, 4); + let y1 = U32::<4>([1, 2, 3, 4]); + let z1 = f32x4(1.0, 2.0, 3.0, 4.0); + let x2 = i32x4(2, 3, 4, 5); + let y2 = U32::<4>([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), U32::<4>([3, 5, 7, 9])); + all_eq_!(simd_add(y2, y1), U32::<4>([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), U32::<4>([2, 6, 12, 20])); + all_eq_!(simd_mul(y2, y1), U32::<4>([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), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_sub(y1, y2), U32::<4>([!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), U32::<4>([1, 1, 1, 1])); + all_eq_!(simd_div(U32::<4>([2, 4, 6, 8]), U32::<4>([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), U32::<4>([0, 0, 0, 0])); + all_eq_!(simd_rem(y2, y1), U32::<4>([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), U32::<4>([1 << 2, 2 << 3, 3 << 4, 4 << 5])); + all_eq_!(simd_shl(y2, y1), U32::<4>([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(U32::<4>([a as u32, b as u32, c as u32, d as u32]), y1), + U32::<4>([(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), U32::<4>([0, 2, 0, 4])); + all_eq_!(simd_and(y2, y1), U32::<4>([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), U32::<4>([3, 3, 7, 5])); + all_eq_!(simd_or(y2, y1), U32::<4>([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), U32::<4>([3, 1, 7, 1])); + all_eq_!(simd_xor(y2, y1), U32::<4>([3, 1, 7, 1])); + + all_eq!(simd_neg(x1), i32x4(-1, -2, -3, -4)); + all_eq!(simd_neg(x2), i32x4(-2, -3, -4, -5)); + all_eq!(simd_neg(z1), f32x4(-1.0, -2.0, -3.0, -4.0)); + all_eq!(simd_neg(z2), f32x4(-2.0, -3.0, -4.0, -5.0)); + + } +} diff --git a/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs new file mode 100644 index 000000000..9736d1b96 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.rs @@ -0,0 +1,38 @@ +// build-fail +// ignore-emscripten +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct i32x4(pub i32, pub i32, pub i32, pub i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct x4<T>(pub T, pub T, pub T, pub T); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +extern "platform-intrinsic" { + fn simd_saturating_add<T>(x: T, y: T) -> T; + fn simd_saturating_sub<T>(x: T, y: T) -> T; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + let y = x4(0_usize, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_saturating_add(x, x); + simd_saturating_add(y, y); + simd_saturating_sub(x, x); + simd_saturating_sub(y, y); + + simd_saturating_add(z, z); + //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + simd_saturating_sub(z, z); + //~^ ERROR expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + } +} diff --git a/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr new file mode 100644 index 000000000..f349cb565 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-2.stderr @@ -0,0 +1,15 @@ +error[E0511]: invalid monomorphization of `simd_saturating_add` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + --> $DIR/generic-arithmetic-saturating-2.rs:33:9 + | +LL | simd_saturating_add(z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_saturating_sub` intrinsic: expected element type `f32` of vector type `f32x4` to be a signed or unsigned integer type + --> $DIR/generic-arithmetic-saturating-2.rs:35:9 + | +LL | simd_saturating_sub(z, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs new file mode 100644 index 000000000..c11d14b99 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs @@ -0,0 +1,91 @@ +// run-pass +// ignore-emscripten + +#![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)] +struct I32<const N: usize>([i32; N]); + +extern "platform-intrinsic" { + fn simd_saturating_add<T>(x: T, y: T) -> T; + fn simd_saturating_sub<T>(x: T, y: T) -> T; +} + +fn main() { + // unsigned + { + const M: u32 = u32::MAX; + + 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; + const MAX: i32 = i32::MAX; + + let a = I32::<4>([1, 2, 3, 4]); + let b = I32::<4>([2, 4, 6, 8]); + let c = I32::<4>([-1, -2, -3, -4]); + let d = I32::<4>([-2, -4, -6, -8]); + + let max = I32::<4>([MAX, MAX, MAX, MAX]); + let max1 = I32::<4>([MAX - 1, MAX - 1, MAX - 1, MAX - 1]); + let min = I32::<4>([MIN, MIN, MIN, MIN]); + let min1 = I32::<4>([MIN + 1, MIN + 1, MIN + 1, MIN + 1]); + + let z = I32::<4>([0, 0, 0, 0]); + + unsafe { + assert_eq!(simd_saturating_add(z, z).0, z.0); + assert_eq!(simd_saturating_add(z, a).0, a.0); + assert_eq!(simd_saturating_add(b, z).0, b.0); + assert_eq!(simd_saturating_add(a, a).0, b.0); + assert_eq!(simd_saturating_add(a, max).0, max.0); + assert_eq!(simd_saturating_add(max, b).0, max.0); + assert_eq!(simd_saturating_add(max1, a).0, max.0); + assert_eq!(simd_saturating_add(min1, z).0, min1.0); + assert_eq!(simd_saturating_add(min, z).0, min.0); + assert_eq!(simd_saturating_add(min1, c).0, min.0); + assert_eq!(simd_saturating_add(min, c).0, min.0); + assert_eq!(simd_saturating_add(min1, d).0, min.0); + assert_eq!(simd_saturating_add(min, d).0, min.0); + + assert_eq!(simd_saturating_sub(b, z).0, b.0); + assert_eq!(simd_saturating_sub(b, a).0, a.0); + assert_eq!(simd_saturating_sub(a, a).0, z.0); + assert_eq!(simd_saturating_sub(a, b).0, c.0); + assert_eq!(simd_saturating_sub(z, max).0, min1.0); + assert_eq!(simd_saturating_sub(min1, z).0, min1.0); + assert_eq!(simd_saturating_sub(min1, a).0, min.0); + assert_eq!(simd_saturating_sub(min1, b).0, min.0); + } + } +} diff --git a/src/test/ui/simd/intrinsic/generic-as.rs b/src/test/ui/simd/intrinsic/generic-as.rs new file mode 100644 index 000000000..a975190a2 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-as.rs @@ -0,0 +1,48 @@ +// run-pass + +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_as<T, U>(x: T) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct V<T>([T; 2]); + +fn main() { + unsafe { + let u = V::<u32>([u32::MIN, u32::MAX]); + let i: V<i16> = simd_as(u); + assert_eq!(i.0[0], u.0[0] as i16); + assert_eq!(i.0[1], u.0[1] as i16); + } + + unsafe { + let f = V::<f32>([f32::MIN, f32::MAX]); + let i: V<i16> = simd_as(f); + assert_eq!(i.0[0], f.0[0] as i16); + assert_eq!(i.0[1], f.0[1] as i16); + } + + unsafe { + let f = V::<f32>([f32::MIN, f32::MAX]); + let u: V<u8> = simd_as(f); + assert_eq!(u.0[0], f.0[0] as u8); + assert_eq!(u.0[1], f.0[1] as u8); + } + + unsafe { + let f = V::<f64>([f64::MIN, f64::MAX]); + let i: V<isize> = simd_as(f); + assert_eq!(i.0[0], f.0[0] as isize); + assert_eq!(i.0[1], f.0[1] as isize); + } + + unsafe { + let f = V::<f64>([f64::MIN, f64::MAX]); + let u: V<usize> = simd_as(f); + assert_eq!(u.0[0], f.0[0] as usize); + assert_eq!(u.0[1], f.0[1] as usize); + } +} diff --git a/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs b/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs new file mode 100644 index 000000000..8c436841b --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-bitmask-pass.rs @@ -0,0 +1,62 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// ignore-endian-big behavior of simd_bitmask is endian-specific + +// 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<T>(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_bitmask<T, U>(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<usize> = Tx4(usize::MAX, 0, usize::MAX, usize::MAX); + + 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/intrinsic/generic-bitmask.rs b/src/test/ui/simd/intrinsic/generic-bitmask.rs new file mode 100644 index 000000000..9a23dae77 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-bitmask.rs @@ -0,0 +1,69 @@ +// build-fail + +// Test that the simd_bitmask intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x2([u32; 2]); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4([u32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x8([u8; 8]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x16([u8; 16]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x32([u8; 32]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x64([u8; 64]); + +extern "platform-intrinsic" { + fn simd_bitmask<T, U>(x: T) -> U; +} + +fn main() { + let m2 = u32x2([0; 2]); + let m4 = u32x4([0; 4]); + let m8 = u8x8([0; 8]); + let m16 = u8x16([0; 16]); + let m32 = u8x32([0; 32]); + let m64 = u8x64([0; 64]); + + unsafe { + let _: u8 = simd_bitmask(m2); + let _: u8 = simd_bitmask(m4); + let _: u8 = simd_bitmask(m8); + let _: u16 = simd_bitmask(m16); + let _: u32 = simd_bitmask(m32); + let _: u64 = simd_bitmask(m64); + + let _: u16 = simd_bitmask(m2); + //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic + + let _: u16 = simd_bitmask(m8); + //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic + + let _: u32 = simd_bitmask(m16); + //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic + + let _: u64 = simd_bitmask(m32); + //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic + + let _: u128 = simd_bitmask(m64); + //~^ ERROR invalid monomorphization of `simd_bitmask` intrinsic + + } +} diff --git a/src/test/ui/simd/intrinsic/generic-bitmask.stderr b/src/test/ui/simd/intrinsic/generic-bitmask.stderr new file mode 100644 index 000000000..0de3f8eea --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-bitmask.stderr @@ -0,0 +1,33 @@ +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]` + --> $DIR/generic-bitmask.rs:53:22 + | +LL | let _: u16 = simd_bitmask(m2); + | ^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u16`, expected `u8` or `[u8; 1]` + --> $DIR/generic-bitmask.rs:56:22 + | +LL | let _: u16 = simd_bitmask(m8); + | ^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u32`, expected `u16` or `[u8; 2]` + --> $DIR/generic-bitmask.rs:59:22 + | +LL | let _: u32 = simd_bitmask(m16); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u64`, expected `u32` or `[u8; 4]` + --> $DIR/generic-bitmask.rs:62:22 + | +LL | let _: u64 = simd_bitmask(m32); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_bitmask` intrinsic: cannot return `u128`, expected `u64` or `[u8; 8]` + --> $DIR/generic-bitmask.rs:65:23 + | +LL | let _: u128 = simd_bitmask(m64); + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-cast-pass.rs b/src/test/ui/simd/intrinsic/generic-cast-pass.rs new file mode 100644 index 000000000..15f232e2c --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-cast-pass.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<T, U>(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/intrinsic/generic-cast-pointer-width.rs b/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs new file mode 100644 index 000000000..b9382310d --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-cast-pointer-width.rs @@ -0,0 +1,21 @@ +// run-pass +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_cast<T, U>(x: T) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct V<T>([T; 4]); + +fn main() { + let u = V::<usize>([0, 1, 2, 3]); + let uu32: V<u32> = unsafe { simd_cast(u) }; + let ui64: V<i64> = unsafe { simd_cast(u) }; + + for (u, (uu32, ui64)) in u.0.iter().zip(uu32.0.iter().zip(ui64.0.iter())) { + assert_eq!(*u as u32, *uu32); + assert_eq!(*u as i64, *ui64); + } +} diff --git a/src/test/ui/simd/intrinsic/generic-cast.rs b/src/test/ui/simd/intrinsic/generic-cast.rs new file mode 100644 index 000000000..4f4fa06b0 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-cast.rs @@ -0,0 +1,43 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + + +extern "platform-intrinsic" { + fn simd_cast<T, U>(x: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_cast::<i32, i32>(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::<i32, i32x4>(0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_cast::<i32x4, i32>(x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_cast::<_, i32x8>(x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 + } +} diff --git a/src/test/ui/simd/intrinsic/generic-cast.stderr b/src/test/ui/simd/intrinsic/generic-cast.stderr new file mode 100644 index 000000000..2226bbbe1 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-cast.stderr @@ -0,0 +1,27 @@ +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:34:9 + | +LL | simd_cast::<i32, i32>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:36:9 + | +LL | simd_cast::<i32, i32x4>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-cast.rs:38:9 + | +LL | simd_cast::<i32x4, i32>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_cast` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i32x8` with length 8 + --> $DIR/generic-cast.rs:40:9 + | +LL | simd_cast::<_, i32x8>(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-comparison-pass.rs b/src/test/ui/simd/intrinsic/generic-comparison-pass.rs new file mode 100644 index 000000000..da5c42a1a --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-comparison-pass.rs @@ -0,0 +1,106 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + +#![feature(repr_simd, platform_intrinsics, concat_idents)] +#![allow(non_camel_case_types)] + +#[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<T, U>(x: T, y: T) -> U; + fn simd_ne<T, U>(x: T, y: T) -> U; + fn simd_lt<T, U>(x: T, y: T) -> U; + fn simd_le<T, U>(x: T, y: T) -> U; + fn simd_gt<T, U>(x: T, y: T) -> U; + fn simd_ge<T, U>(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(f32::NAN, f1.1, f32::NAN, f2.3); + + unsafe { + tests! { + f1, f4; + f2, f4; + f4, f4; + } + } +} diff --git a/src/test/ui/simd/intrinsic/generic-comparison.rs b/src/test/ui/simd/intrinsic/generic-comparison.rs new file mode 100644 index 000000000..3cd38042f --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-comparison.rs @@ -0,0 +1,67 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i16x8(i16, i16, i16, i16, + i16, i16, i16, i16); + +extern "platform-intrinsic" { + fn simd_eq<T, U>(x: T, y: T) -> U; + fn simd_ne<T, U>(x: T, y: T) -> U; + fn simd_lt<T, U>(x: T, y: T) -> U; + fn simd_le<T, U>(x: T, y: T) -> U; + fn simd_gt<T, U>(x: T, y: T) -> U; + fn simd_ge<T, U>(x: T, y: T) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_eq::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ne::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_lt::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_le::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_gt::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_ge::<i32, i32>(0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_eq::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ne::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_lt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_le::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_gt::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + simd_ge::<_, i32>(x, x); + //~^ ERROR expected SIMD return type, found non-SIMD `i32` + + simd_eq::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ne::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_lt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_le::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_gt::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + simd_ge::<_, i16x8>(x, x); +//~^ ERROR return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + } +} diff --git a/src/test/ui/simd/intrinsic/generic-comparison.stderr b/src/test/ui/simd/intrinsic/generic-comparison.stderr new file mode 100644 index 000000000..0eae2688b --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-comparison.stderr @@ -0,0 +1,111 @@ +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:28:9 + | +LL | simd_eq::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:30:9 + | +LL | simd_ne::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:32:9 + | +LL | simd_lt::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:34:9 + | +LL | simd_le::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:36:9 + | +LL | simd_gt::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:38:9 + | +LL | simd_ge::<i32, i32>(0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:41:9 + | +LL | simd_eq::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:43:9 + | +LL | simd_ne::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:45:9 + | +LL | simd_lt::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:47:9 + | +LL | simd_le::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:49:9 + | +LL | simd_gt::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected SIMD return type, found non-SIMD `i32` + --> $DIR/generic-comparison.rs:51:9 + | +LL | simd_ge::<_, i32>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_eq` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:54:9 + | +LL | simd_eq::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ne` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:56:9 + | +LL | simd_ne::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_lt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:58:9 + | +LL | simd_lt::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_le` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:60:9 + | +LL | simd_le::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_gt` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:62:9 + | +LL | simd_gt::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_ge` intrinsic: expected return type with length 4 (same as input type `i32x4`), found `i16x8` with length 8 + --> $DIR/generic-comparison.rs:64:9 + | +LL | simd_ge::<_, i16x8>(x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 18 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-elements-pass.rs b/src/test/ui/simd/intrinsic/generic-elements-pass.rs new file mode 100644 index 000000000..3c913c0ad --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-elements-pass.rs @@ -0,0 +1,102 @@ +// run-pass +// ignore-emscripten FIXME(#45351) hits an LLVM assert + +#![feature(repr_simd, platform_intrinsics)] +#![feature(inline_const)] + +#[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 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<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; + + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8<T, U>(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 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(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(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 y4 = i32x4(140, 141, 142, 143); + let y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); + unsafe { + all_eq!(simd_shuffle2(x2, y2, const { [3u32, 0] }), i32x2(121, 20)); + all_eq!(simd_shuffle4(x2, y2, const { [3u32, 0, 1, 2] }), i32x4(121, 20, 21, 120)); + all_eq!(simd_shuffle8(x2, y2, const { [3u32, 0, 1, 2, 1, 2, 3, 0] }), + i32x8(121, 20, 21, 120, 21, 120, 121, 20)); + + all_eq!(simd_shuffle2(x4, y4, const { [7u32, 2] }), i32x2(143, 42)); + all_eq!(simd_shuffle4(x4, y4, const { [7u32, 2, 5, 0] }), i32x4(143, 42, 141, 40)); + all_eq!(simd_shuffle8(x4, y4, const { [7u32, 2, 5, 0, 3, 6, 4, 1] }), + i32x8(143, 42, 141, 40, 43, 142, 140, 41)); + + all_eq!(simd_shuffle2(x8, y8, const { [11u32, 5] }), i32x2(183, 85)); + all_eq!(simd_shuffle4(x8, y8, const { [11u32, 5, 15, 0] }), i32x4(183, 85, 187, 80)); + all_eq!(simd_shuffle8(x8, y8, const { [11u32, 5, 15, 0, 3, 8, 12, 1] }), + i32x8(183, 85, 187, 80, 83, 180, 184, 81)); + } + +} diff --git a/src/test/ui/simd/intrinsic/generic-elements.rs b/src/test/ui/simd/intrinsic/generic-elements.rs new file mode 100644 index 000000000..abde69163 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-elements.rs @@ -0,0 +1,77 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics, rustc_attrs)] + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct i32x8(i32, i32, i32, i32, + i32, i32, i32, i32); + +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x2(f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +#[derive(Copy, Clone)] +#[allow(non_camel_case_types)] +struct f32x8(f32, f32, f32, f32, + f32, f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert<T, E>(x: T, idx: u32, y: E) -> T; + fn simd_extract<T, E>(x: T, idx: u32) -> E; + + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; + fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; + fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U; +} + +fn main() { + let x = i32x4(0, 0, 0, 0); + + unsafe { + simd_insert(0, 0, 0); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + simd_insert(x, 0, 1.0); + //~^ ERROR expected inserted type `i32` (element of input `i32x4`), found `f64` + simd_extract::<_, f32>(x, 0); + //~^ ERROR expected return type `i32` (element of input `i32x4`), found `f32` + + const IDX2: [u32; 2] = [0; 2]; + simd_shuffle2::<i32, i32>(0, 0, IDX2); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + const IDX4: [u32; 4] = [0; 4]; + simd_shuffle4::<i32, i32>(0, 0, IDX4); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + const IDX8: [u32; 8] = [0; 8]; + simd_shuffle8::<i32, i32>(0, 0, IDX8); + //~^ ERROR expected SIMD input type, found non-SIMD `i32` + + simd_shuffle2::<_, f32x2>(x, x, IDX2); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + simd_shuffle4::<_, f32x4>(x, x, IDX4); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + simd_shuffle8::<_, f32x8>(x, x, IDX8); +//~^ ERROR element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + + simd_shuffle2::<_, i32x8>(x, x, IDX2); + //~^ ERROR expected return type of length 2, found `i32x8` with length 8 + simd_shuffle4::<_, i32x8>(x, x, IDX4); + //~^ ERROR expected return type of length 4, found `i32x8` with length 8 + simd_shuffle8::<_, i32x2>(x, x, IDX8); + //~^ ERROR expected return type of length 8, found `i32x2` with length 2 + } +} diff --git a/src/test/ui/simd/intrinsic/generic-elements.stderr b/src/test/ui/simd/intrinsic/generic-elements.stderr new file mode 100644 index 000000000..5b423f704 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-elements.stderr @@ -0,0 +1,75 @@ +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:46:9 + | +LL | simd_insert(0, 0, 0); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_insert` intrinsic: expected inserted type `i32` (element of input `i32x4`), found `f64` + --> $DIR/generic-elements.rs:48:9 + | +LL | simd_insert(x, 0, 1.0); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_extract` intrinsic: expected return type `i32` (element of input `i32x4`), found `f32` + --> $DIR/generic-elements.rs:50:9 + | +LL | simd_extract::<_, f32>(x, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:54:9 + | +LL | simd_shuffle2::<i32, i32>(0, 0, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:57:9 + | +LL | simd_shuffle4::<i32, i32>(0, 0, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected SIMD input type, found non-SIMD `i32` + --> $DIR/generic-elements.rs:60:9 + | +LL | simd_shuffle8::<i32, i32>(0, 0, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x2` with element type `f32` + --> $DIR/generic-elements.rs:63:9 + | +LL | simd_shuffle2::<_, f32x2>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x4` with element type `f32` + --> $DIR/generic-elements.rs:65:9 + | +LL | simd_shuffle4::<_, f32x4>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return element type `i32` (element of input `i32x4`), found `f32x8` with element type `f32` + --> $DIR/generic-elements.rs:67:9 + | +LL | simd_shuffle8::<_, f32x8>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: expected return type of length 2, found `i32x8` with length 8 + --> $DIR/generic-elements.rs:70:9 + | +LL | simd_shuffle2::<_, i32x8>(x, x, IDX2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: expected return type of length 4, found `i32x8` with length 8 + --> $DIR/generic-elements.rs:72:9 + | +LL | simd_shuffle4::<_, i32x8>(x, x, IDX4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: expected return type of length 8, found `i32x2` with length 2 + --> $DIR/generic-elements.rs:74:9 + | +LL | simd_shuffle8::<_, i32x2>(x, x, IDX8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 12 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-gather-pass.rs b/src/test/ui/simd/intrinsic/generic-gather-pass.rs new file mode 100644 index 000000000..805caebe5 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-gather-pass.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<T>(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T; + fn simd_scatter<T, U, V>(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/intrinsic/generic-reduction-pass.rs b/src/test/ui/simd/intrinsic/generic-reduction-pass.rs new file mode 100644 index 000000000..4a54afee8 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-reduction-pass.rs @@ -0,0 +1,155 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten + +// 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); + +extern "platform-intrinsic" { + fn simd_reduce_add_unordered<T, U>(x: T) -> U; + fn simd_reduce_mul_unordered<T, U>(x: T) -> U; + fn simd_reduce_add_ordered<T, U>(x: T, acc: U) -> U; + fn simd_reduce_mul_ordered<T, U>(x: T, acc: U) -> U; + fn simd_reduce_min<T, U>(x: T) -> U; + fn simd_reduce_max<T, U>(x: T) -> U; + fn simd_reduce_min_nanless<T, U>(x: T) -> U; + fn simd_reduce_max_nanless<T, U>(x: T) -> U; + fn simd_reduce_and<T, U>(x: T) -> U; + fn simd_reduce_or<T, U>(x: T) -> U; + fn simd_reduce_xor<T, U>(x: T) -> U; + fn simd_reduce_all<T>(x: T) -> bool; + fn simd_reduce_any<T>(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; + 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/intrinsic/generic-reduction.rs b/src/test/ui/simd/intrinsic/generic-reduction.rs new file mode 100644 index 000000000..ede4b26d1 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-reduction.rs @@ -0,0 +1,58 @@ +// build-fail +// ignore-emscripten + +// Test that the simd_reduce_{op} intrinsics produce ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + + +extern "platform-intrinsic" { + fn simd_reduce_add_ordered<T, U>(x: T, y: U) -> U; + fn simd_reduce_mul_ordered<T, U>(x: T, y: U) -> U; + fn simd_reduce_and<T, U>(x: T) -> U; + fn simd_reduce_or<T, U>(x: T) -> U; + fn simd_reduce_xor<T, U>(x: T) -> U; + fn simd_reduce_all<T>(x: T) -> bool; + fn simd_reduce_any<T>(x: T) -> bool; +} + +fn main() { + let x = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_reduce_add_ordered(z, 0); + //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` + simd_reduce_mul_ordered(z, 1); + //~^ ERROR expected return type `f32` (element of input `f32x4`), found `i32` + + let _: f32 = simd_reduce_and(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_or(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + let _: f32 = simd_reduce_xor(x); + //~^ ERROR expected return type `u32` (element of input `u32x4`), found `f32` + + let _: f32 = simd_reduce_and(z); + //~^ ERROR unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_or(z); + //~^ ERROR unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` + let _: f32 = simd_reduce_xor(z); + //~^ ERROR unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` + + let _: bool = simd_reduce_all(z); + //~^ ERROR unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` + let _: bool = simd_reduce_any(z); + //~^ ERROR unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` + } +} diff --git a/src/test/ui/simd/intrinsic/generic-reduction.stderr b/src/test/ui/simd/intrinsic/generic-reduction.stderr new file mode 100644 index 000000000..1028faf69 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-reduction.stderr @@ -0,0 +1,63 @@ +error[E0511]: invalid monomorphization of `simd_reduce_add_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` + --> $DIR/generic-reduction.rs:34:9 + | +LL | simd_reduce_add_ordered(z, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_mul_ordered` intrinsic: expected return type `f32` (element of input `f32x4`), found `i32` + --> $DIR/generic-reduction.rs:36:9 + | +LL | simd_reduce_mul_ordered(z, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:39:22 + | +LL | let _: f32 = simd_reduce_and(x); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:41:22 + | +LL | let _: f32 = simd_reduce_or(x); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: expected return type `u32` (element of input `u32x4`), found `f32` + --> $DIR/generic-reduction.rs:43:22 + | +LL | let _: f32 = simd_reduce_xor(x); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_and` intrinsic: unsupported simd_reduce_and from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:46:22 + | +LL | let _: f32 = simd_reduce_and(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_or` intrinsic: unsupported simd_reduce_or from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:48:22 + | +LL | let _: f32 = simd_reduce_or(z); + | ^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_xor` intrinsic: unsupported simd_reduce_xor from `f32x4` with element `f32` to `f32` + --> $DIR/generic-reduction.rs:50:22 + | +LL | let _: f32 = simd_reduce_xor(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_all` intrinsic: unsupported simd_reduce_all from `f32x4` with element `f32` to `bool` + --> $DIR/generic-reduction.rs:53:23 + | +LL | let _: bool = simd_reduce_all(z); + | ^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_reduce_any` intrinsic: unsupported simd_reduce_any from `f32x4` with element `f32` to `bool` + --> $DIR/generic-reduction.rs:55:23 + | +LL | let _: bool = simd_reduce_any(z); + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-select-pass.rs b/src/test/ui/simd/intrinsic/generic-select-pass.rs new file mode 100644 index 000000000..b850cf975 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-select-pass.rs @@ -0,0 +1,195 @@ +// run-pass +#![allow(non_camel_case_types)] + +// ignore-emscripten +// ignore-endian-big 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<T, U>(x: T, a: U, b: U) -> U; + fn simd_select_bitmask<T, U>(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); + } + + unsafe { + let a = u32x4(0, 1, 2, 3); + let b = u32x4(4, 5, 6, 7); + + let r: u32x4 = simd_select_bitmask(0u8, a, b); + let e = b; + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0xfu8, a, b); + let e = a; + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b0101u8, a, b); + let e = u32x4(0, 5, 2, 7); + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b1010u8, a, b); + let e = u32x4(4, 1, 6, 3); + assert_eq!(r, e); + + let r: u32x4 = simd_select_bitmask(0b1100u8, a, b); + let e = u32x4(4, 5, 2, 3); + assert_eq!(r, e); + } +} diff --git a/src/test/ui/simd/intrinsic/generic-select.rs b/src/test/ui/simd/intrinsic/generic-select.rs new file mode 100644 index 000000000..248e82ea2 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-select.rs @@ -0,0 +1,63 @@ +// build-fail + +// Test that the simd_select intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct f32x4(pub f32, pub f32, pub f32, pub f32); + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct u32x4(pub u32, pub u32, pub u32, pub u32); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq)] +struct b8x4(pub i8, pub i8, pub i8, pub i8); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq)] +struct b8x8(pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8, pub i8); + +extern "platform-intrinsic" { + fn simd_select<T, U>(x: T, a: U, b: U) -> U; + fn simd_select_bitmask<T, U>(x: T, a: U, b: U) -> U; +} + +fn main() { + let m4 = b8x4(0, 0, 0, 0); + let m8 = b8x8(0, 0, 0, 0, 0, 0, 0, 0); + let x = u32x4(0, 0, 0, 0); + let z = f32x4(0.0, 0.0, 0.0, 0.0); + + unsafe { + simd_select(m4, x, x); + + simd_select(m8, x, x); + //~^ ERROR mismatched lengths: mask length `8` != other vector length `4` + + simd_select(x, x, x); + //~^ ERROR mask element type is `u32`, expected `i_` + + simd_select(z, z, z); + //~^ ERROR mask element type is `f32`, expected `i_` + + simd_select(m4, 0u32, 1u32); + //~^ ERROR found non-SIMD `u32` + + simd_select_bitmask(0u16, x, x); + //~^ ERROR invalid bitmask `u16`, expected `u8` or `[u8; 1]` + + simd_select_bitmask(0u8, 1u32, 2u32); + //~^ ERROR found non-SIMD `u32` + + simd_select_bitmask(0.0f32, x, x); + //~^ ERROR invalid bitmask `f32`, expected `u8` or `[u8; 1]` + + simd_select_bitmask("x", x, x); + //~^ ERROR invalid bitmask `&str`, expected `u8` or `[u8; 1]` + } +} diff --git a/src/test/ui/simd/intrinsic/generic-select.stderr b/src/test/ui/simd/intrinsic/generic-select.stderr new file mode 100644 index 000000000..d576f1bc7 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-select.stderr @@ -0,0 +1,51 @@ +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mismatched lengths: mask length `8` != other vector length `4` + --> $DIR/generic-select.rs:39:9 + | +LL | simd_select(m8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `u32`, expected `i_` + --> $DIR/generic-select.rs:42:9 + | +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: mask element type is `f32`, expected `i_` + --> $DIR/generic-select.rs:45:9 + | +LL | simd_select(z, z, z); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/generic-select.rs:48:9 + | +LL | simd_select(m4, 0u32, 1u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `u16`, expected `u8` or `[u8; 1]` + --> $DIR/generic-select.rs:51:9 + | +LL | simd_select_bitmask(0u16, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: expected SIMD argument type, found non-SIMD `u32` + --> $DIR/generic-select.rs:54:9 + | +LL | simd_select_bitmask(0u8, 1u32, 2u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `f32`, expected `u8` or `[u8; 1]` + --> $DIR/generic-select.rs:57:9 + | +LL | simd_select_bitmask(0.0f32, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_select_bitmask` intrinsic: invalid bitmask `&str`, expected `u8` or `[u8; 1]` + --> $DIR/generic-select.rs:60:9 + | +LL | simd_select_bitmask("x", x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/generic-shuffle.rs b/src/test/ui/simd/intrinsic/generic-shuffle.rs new file mode 100644 index 000000000..9611780ac --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-shuffle.rs @@ -0,0 +1,33 @@ +// build-fail + +// Test that the simd_shuffle intrinsic produces ok-ish error +// messages when misused. + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone)] +pub struct Simd<T, const N: usize>([T; N]); + +extern "platform-intrinsic" { + fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; +} + +fn main() { + const I: [u32; 2] = [0; 2]; + const I2: [f32; 2] = [0.; 2]; + let v = Simd::<u32, 4>([0; 4]); + + unsafe { + let _: Simd<u32, 2> = simd_shuffle(v, v, I); + + let _: Simd<u32, 4> = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + + let _: Simd<f32, 2> = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + + let _: Simd<u32, 2> = simd_shuffle(v, v, I2); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + } +} diff --git a/src/test/ui/simd/intrinsic/generic-shuffle.stderr b/src/test/ui/simd/intrinsic/generic-shuffle.stderr new file mode 100644 index 000000000..81e641612 --- /dev/null +++ b/src/test/ui/simd/intrinsic/generic-shuffle.stderr @@ -0,0 +1,21 @@ +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return type of length 2, found `Simd<u32, 4>` with length 4 + --> $DIR/generic-shuffle.rs:24:31 + | +LL | let _: Simd<u32, 4> = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: expected return element type `u32` (element of input `Simd<u32, 4>`), found `Simd<f32, 2>` with element type `f32` + --> $DIR/generic-shuffle.rs:27:31 + | +LL | let _: Simd<f32, 2> = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: simd_shuffle index must be an array of `u32`, got `[f32; 2]` + --> $DIR/generic-shuffle.rs:30:31 + | +LL | let _: Simd<u32, 2> = simd_shuffle(v, v, I2); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs b/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs new file mode 100644 index 000000000..7221b3ab7 --- /dev/null +++ b/src/test/ui/simd/intrinsic/inlining-issue67557-ice.rs @@ -0,0 +1,26 @@ +// This used to cause an ICE for an internal index out of range due to simd_shuffle_indices being +// passed the wrong Instance, causing issues with inlining. See #67557. +// +// run-pass +// compile-flags: -Zmir-opt-level=4 +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; +} + +#[repr(simd)] +#[derive(Debug, PartialEq)] +struct Simd2(u8, u8); + +fn main() { + unsafe { + let _: Simd2 = inline_me(); + } +} + +#[inline(always)] +unsafe fn inline_me() -> Simd2 { + const IDX: [u32; 2] = [0, 3]; + simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) +} diff --git a/src/test/ui/simd/intrinsic/inlining-issue67557.rs b/src/test/ui/simd/intrinsic/inlining-issue67557.rs new file mode 100644 index 000000000..0d1542709 --- /dev/null +++ b/src/test/ui/simd/intrinsic/inlining-issue67557.rs @@ -0,0 +1,42 @@ +// This used to cause assert_10_13 to unexpectingly fail, due to simd_shuffle_indices being passed +// the wrong Instance, causing issues with inlining. See #67557. +// +// run-pass +// compile-flags: -Zmir-opt-level=4 +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; +} + +#[repr(simd)] +#[derive(Debug, PartialEq)] +struct Simd2(u8, u8); + +fn main() { + unsafe { + const IDX: [u32; 2] = [0, 1]; + let p_res: Simd2 = simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX); + let a_res: Simd2 = inline_me(); + + assert_10_11(p_res); + assert_10_13(a_res); + } +} + +#[inline(never)] +fn assert_10_11(x: Simd2) { + assert_eq!(x, Simd2(10, 11)); +} + +#[inline(never)] +fn assert_10_13(x: Simd2) { + assert_eq!(x, Simd2(10, 13)); +} + + +#[inline(always)] +unsafe fn inline_me() -> Simd2 { + const IDX: [u32; 2] = [0, 3]; + simd_shuffle2(Simd2(10, 11), Simd2(12, 13), IDX) +} diff --git a/src/test/ui/simd/intrinsic/issue-85855.rs b/src/test/ui/simd/intrinsic/issue-85855.rs new file mode 100644 index 000000000..f276fbd66 --- /dev/null +++ b/src/test/ui/simd/intrinsic/issue-85855.rs @@ -0,0 +1,19 @@ +// Check that appropriate errors are reported if an intrinsic is defined +// with the wrong number of generic lifetime/type/const parameters, and +// that no ICE occurs in these cases. + +#![feature(platform_intrinsics)] +#![crate_type="lib"] + +extern "platform-intrinsic" { + fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of lifetime parameters + + fn simd_add<'a, T>(x: T, y: T) -> T; + + fn simd_sub<T, U>(x: T, y: U); + //~^ ERROR: intrinsic has wrong number of type parameters + + fn simd_mul<T, const N: usize>(x: T, y: T); + //~^ ERROR: intrinsic has wrong number of const parameters +} diff --git a/src/test/ui/simd/intrinsic/issue-85855.stderr b/src/test/ui/simd/intrinsic/issue-85855.stderr new file mode 100644 index 000000000..fb2f1fbc5 --- /dev/null +++ b/src/test/ui/simd/intrinsic/issue-85855.stderr @@ -0,0 +1,21 @@ +error[E0094]: intrinsic has wrong number of lifetime parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:9:27 + | +LL | fn simd_saturating_add<'a, T: 'a>(x: T, y: T); + | ^^^^^^^^^^^ expected 0 lifetime parameters + +error[E0094]: intrinsic has wrong number of type parameters: found 2, expected 1 + --> $DIR/issue-85855.rs:14:16 + | +LL | fn simd_sub<T, U>(x: T, y: U); + | ^^^^^^ expected 1 type parameter + +error[E0094]: intrinsic has wrong number of const parameters: found 1, expected 0 + --> $DIR/issue-85855.rs:17:16 + | +LL | fn simd_mul<T, const N: usize>(x: T, y: T); + | ^^^^^^^^^^^^^^^^^^^ expected 0 const parameters + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0094`. diff --git a/src/test/ui/simd/issue-17170.rs b/src/test/ui/simd/issue-17170.rs new file mode 100644 index 000000000..8d70dacdc --- /dev/null +++ b/src/test/ui/simd/issue-17170.rs @@ -0,0 +1,11 @@ +// run-pass +#![feature(repr_simd)] + +#[repr(simd)] +struct T(f64, f64, f64); + +static X: T = T(0.0, 0.0, 0.0); + +fn main() { + let _ = X; +} diff --git a/src/test/ui/simd/issue-32947.rs b/src/test/ui/simd/issue-32947.rs new file mode 100644 index 000000000..b07def21e --- /dev/null +++ b/src/test/ui/simd/issue-32947.rs @@ -0,0 +1,24 @@ +// run-pass +// ignore-emscripten FIXME(#45351) + +#![feature(repr_simd, test)] + +extern crate test; + +#[repr(simd)] +pub struct Mu64(pub u64, pub u64, pub u64, pub u64); + +fn main() { + // This ensures an unaligned pointer even in optimized builds, though LLVM + // gets enough type information to actually not mess things up in that case, + // but at the time of writing this, it's enough to trigger the bug in + // non-optimized builds + unsafe { + let memory = &mut [0u64; 8] as *mut _ as *mut u8; + let misaligned_ptr: &mut [u8; 32] = { + std::mem::transmute(memory.offset(1)) + }; + *misaligned_ptr = std::mem::transmute(Mu64(1, 1, 1, 1)); + test::black_box(memory); + } +} diff --git a/src/test/ui/simd/issue-39720.rs b/src/test/ui/simd/issue-39720.rs new file mode 100644 index 000000000..8cf841f93 --- /dev/null +++ b/src/test/ui/simd/issue-39720.rs @@ -0,0 +1,22 @@ +// run-pass +// ignore-emscripten FIXME(#45351) + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +#[derive(Copy, Clone, Debug)] +pub struct Char3(pub i8, pub i8, pub i8); + +#[repr(simd)] +#[derive(Copy, Clone, Debug)] +pub struct Short3(pub i16, pub i16, pub i16); + +extern "platform-intrinsic" { + fn simd_cast<T, U>(x: T) -> U; +} + +fn main() { + let cast: Short3 = unsafe { simd_cast(Char3(10, -3, -9)) }; + + println!("{:?}", cast); +} diff --git a/src/test/ui/simd/issue-85915-simd-ptrs.rs b/src/test/ui/simd/issue-85915-simd-ptrs.rs new file mode 100644 index 000000000..6fe415545 --- /dev/null +++ b/src/test/ui/simd/issue-85915-simd-ptrs.rs @@ -0,0 +1,67 @@ +// run-pass +// ignore-emscripten + +// Short form of the generic gather/scatter tests, +// verifying simd([*const T; N]) and simd([*mut T; N]) pass typeck and work. +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct cptrx4<T>([*const T; 4]); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct mptrx4<T>([*mut T; 4]); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct f32x4([f32; 4]); + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct i32x4([i32; 4]); + +extern "platform-intrinsic" { + fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T; + fn simd_scatter<T, U, V>(x: T, y: U, z: V) -> (); +} + +fn main() { + let mut x = [0_f32, 1., 2., 3., 4., 5., 6., 7.]; + + let default = f32x4([-3_f32, -3., -3., -3.]); + let s_strided = f32x4([0_f32, 2., -3., 6.]); + let mask = i32x4([-1_i32, -1, 0, -1]); + + // reading from *const + unsafe { + let pointer = &x as *const f32; + let pointers = cptrx4([ + 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); + } + + // writing to *mut + unsafe { + let pointer = &mut x as *mut f32; + let pointers = mptrx4([ + pointer.offset(0) as *mut f32, + pointer.offset(2), + pointer.offset(4), + pointer.offset(6) + ]); + + let values = f32x4([42_f32, 43_f32, 44_f32, 45_f32]); + simd_scatter(values, pointers, mask); + + assert_eq!(x, [42., 1., 43., 3., 4., 5., 45., 7.]); + } +} diff --git a/src/test/ui/simd/issue-89193.rs b/src/test/ui/simd/issue-89193.rs new file mode 100644 index 000000000..79c4e6a31 --- /dev/null +++ b/src/test/ui/simd/issue-89193.rs @@ -0,0 +1,51 @@ +// run-pass + +// Test that simd gather instructions on slice of usize don't cause crash +// See issue #89183 - https://github.com/rust-lang/rust/issues/89193 + +#![feature(repr_simd, platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] +#[derive(Copy, Clone, PartialEq, Debug)] +struct x4<T>(pub T, pub T, pub T, pub T); + +extern "platform-intrinsic" { + fn simd_gather<T, U, V>(x: T, y: U, z: V) -> T; +} + +fn main() { + let x: [usize; 4] = [10, 11, 12, 13]; + let default = x4(0_usize, 1, 2, 3); + let mask = x4(1_i32, 1, 1, 1); + let expected = x4(10_usize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const usize; + let pointers = x4( + pointer.offset(0) as *const usize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } + + // and again for isize + let x: [isize; 4] = [10, 11, 12, 13]; + let default = x4(0_isize, 1, 2, 3); + let expected = x4(10_isize, 11, 12, 13); + + unsafe { + let pointer = &x[0] as *const isize; + let pointers = x4( + pointer.offset(0) as *const isize, + pointer.offset(1), + pointer.offset(2), + pointer.offset(3) + ); + let result = simd_gather(default, pointers, mask); + assert_eq!(result, expected); + } +} diff --git a/src/test/ui/simd/libm_no_std_cant_float.rs b/src/test/ui/simd/libm_no_std_cant_float.rs new file mode 100644 index 000000000..50ac8e208 --- /dev/null +++ b/src/test/ui/simd/libm_no_std_cant_float.rs @@ -0,0 +1,22 @@ +#![crate_type = "rlib"] +#![no_std] +#![feature(portable_simd)] +use core::simd::f32x4; +use core::simd::SimdFloat; + +// For SIMD float ops, the LLIR version which is used to implement the portable +// forms of them may become calls to math.h AKA libm. So, we can't guarantee +// we can compile them for #![no_std] crates. +// Someday we may solve this. +// Until then, this test at least guarantees these functions require std. +fn guarantee_no_std_nolibm_calls() -> f32x4 { + let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]); + let x2 = x + x; + let _xc = x.ceil(); //~ ERROR E0599 + let _xf = x.floor(); //~ ERROR E0599 + let _xr = x.round(); //~ ERROR E0599 + let _xt = x.trunc(); //~ ERROR E0599 + let _xfma = x.mul_add(x, x); //~ ERROR E0599 + let _xsqrt = x.sqrt(); //~ ERROR E0599 + x2.abs() * x2 +} diff --git a/src/test/ui/simd/libm_no_std_cant_float.stderr b/src/test/ui/simd/libm_no_std_cant_float.stderr new file mode 100644 index 000000000..97e0b7efe --- /dev/null +++ b/src/test/ui/simd/libm_no_std_cant_float.stderr @@ -0,0 +1,39 @@ +error[E0599]: no method named `ceil` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:15:17 + | +LL | let _xc = x.ceil(); + | ^^^^ method not found in `Simd<f32, 4>` + +error[E0599]: no method named `floor` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:16:17 + | +LL | let _xf = x.floor(); + | ^^^^^ method not found in `Simd<f32, 4>` + +error[E0599]: no method named `round` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:17:17 + | +LL | let _xr = x.round(); + | ^^^^^ method not found in `Simd<f32, 4>` + +error[E0599]: no method named `trunc` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:18:17 + | +LL | let _xt = x.trunc(); + | ^^^^^ method not found in `Simd<f32, 4>` + +error[E0599]: no method named `mul_add` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:19:19 + | +LL | let _xfma = x.mul_add(x, x); + | ^^^^^^^ method not found in `Simd<f32, 4>` + +error[E0599]: no method named `sqrt` found for struct `Simd` in the current scope + --> $DIR/libm_no_std_cant_float.rs:20:20 + | +LL | let _xsqrt = x.sqrt(); + | ^^^^ method not found in `Simd<f32, 4>` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/simd/libm_std_can_float.rs b/src/test/ui/simd/libm_std_can_float.rs new file mode 100644 index 000000000..1c520856e --- /dev/null +++ b/src/test/ui/simd/libm_std_can_float.rs @@ -0,0 +1,23 @@ +// run-pass + +// This is the converse of the other libm test. +#![feature(portable_simd)] +use std::simd::f32x4; +use std::simd::{SimdFloat, StdFloat}; + +// For SIMD float ops, the LLIR version which is used to implement the portable +// forms of them may become calls to math.h AKA libm. So, we can't guarantee +// we can compile them for #![no_std] crates. +// +// However, we can expose some of these ops via an extension trait. +fn main() { + let x = f32x4::from_array([0.1, 0.5, 0.6, -1.5]); + let x2 = x + x; + let _xc = x.ceil(); + let _xf = x.floor(); + let _xr = x.round(); + let _xt = x.trunc(); + let _xfma = x.mul_add(x, x); + let _xsqrt = x.sqrt(); + let _ = x2.abs() * x2; +} diff --git a/src/test/ui/simd/monomorphize-shuffle-index.rs b/src/test/ui/simd/monomorphize-shuffle-index.rs new file mode 100644 index 000000000..2467baa08 --- /dev/null +++ b/src/test/ui/simd/monomorphize-shuffle-index.rs @@ -0,0 +1,40 @@ +//run-pass +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd<T, const N: usize>([T; N]); + +trait Shuffle<const N: usize> { + const I: [u32; N]; + + unsafe fn shuffle<T, const M: usize>(&self, a: Simd<T, M>, b: Simd<T, M>) -> Simd<T, N> { + simd_shuffle(a, b, Self::I) + } +} + +fn main() { + struct I1; + impl Shuffle<4> for I1 { + const I: [u32; 4] = [0, 2, 4, 6]; + } + + struct I2; + impl Shuffle<2> for I2 { + const I: [u32; 2] = [1, 5]; + } + + let a = Simd::<u8, 4>([0, 1, 2, 3]); + let b = Simd::<u8, 4>([4, 5, 6, 7]); + unsafe { + let x: Simd<u8, 4> = I1.shuffle(a, b); + assert_eq!(x.0, [0, 2, 4, 6]); + + let y: Simd<u8, 2> = I2.shuffle(a, b); + assert_eq!(y.0, [1, 5]); + } +} diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.rs b/src/test/ui/simd/portable-intrinsics-arent-exposed.rs new file mode 100644 index 000000000..667c8b67b --- /dev/null +++ b/src/test/ui/simd/portable-intrinsics-arent-exposed.rs @@ -0,0 +1,9 @@ +// May not matter, since people can use them with a nightly feature. +// However this tests to guarantee they don't leak out via portable_simd, +// and thus don't accidentally get stabilized. +use core::simd::intrinsics; //~ERROR E0433 +use std::simd::intrinsics; //~ERROR E0432 + +fn main() { + () +} diff --git a/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr new file mode 100644 index 000000000..870f4064d --- /dev/null +++ b/src/test/ui/simd/portable-intrinsics-arent-exposed.stderr @@ -0,0 +1,18 @@ +error[E0433]: failed to resolve: maybe a missing crate `core`? + --> $DIR/portable-intrinsics-arent-exposed.rs:4:5 + | +LL | use core::simd::intrinsics; + | ^^^^ maybe a missing crate `core`? + | + = help: consider adding `extern crate core` to use the `core` crate + +error[E0432]: unresolved import `std::simd::intrinsics` + --> $DIR/portable-intrinsics-arent-exposed.rs:5:5 + | +LL | use std::simd::intrinsics; + | ^^^^^^^^^^^^^^^^^^^^^ no `intrinsics` in `simd` + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0432, E0433. +For more information about an error, try `rustc --explain E0432`. diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.rs b/src/test/ui/simd/shuffle-not-out-of-bounds.rs new file mode 100644 index 000000000..0dee3a0e8 --- /dev/null +++ b/src/test/ui/simd/shuffle-not-out-of-bounds.rs @@ -0,0 +1,87 @@ +// build-fail +#![allow(non_camel_case_types)] +#![feature(repr_simd, platform_intrinsics)] + +// Test for #73542 to verify out-of-bounds shuffle vectors do not compile. + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x2([u8; 2]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x4([u8; 4]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x8([u8; 8]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x16([u8; 16]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x32([u8; 32]); + +#[repr(simd)] +#[derive(Copy, Clone)] +struct u8x64([u8; 64]); + +extern "platform-intrinsic" { + pub fn simd_shuffle2<T, U>(x: T, y: T, idx: [u32; 2]) -> U; + pub fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U; + pub fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U; + pub fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U; + pub fn simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U; + pub fn simd_shuffle64<T, U>(x: T, y: T, idx: [u32; 64]) -> U; +} + +// Test vectors by lane size. Since LLVM does not distinguish between a shuffle +// over two f32s and a shuffle over two u64s, or any other such combination, +// it is not necessary to test every possible vector, only lane counts. +macro_rules! test_shuffle_lanes { + ($n:literal, $x:ident, $y:ident) => { + unsafe { + let shuffle: $x = { + const ARR: [u32; $n] = { + let mut arr = [0; $n]; + arr[0] = $n * 2; + arr + }; + let mut n: u8 = $n; + let vals = [0; $n].map(|_| { n = n - 1; n }); + let vec1 = $x(vals); + let vec2 = $x(vals); + $y(vec1, vec2, ARR) + }; + } + } +} +//~^^^^^ ERROR: invalid monomorphization of `simd_shuffle2` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle4` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle8` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle16` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle32` intrinsic +//~| ERROR: invalid monomorphization of `simd_shuffle64` intrinsic +// Because the test is mostly embedded in a macro, all the errors have the same origin point. +// And unfortunately, standard comments, as in the UI test harness, disappear in macros! + +fn main() { + test_shuffle_lanes!(2, u8x2, simd_shuffle2); + test_shuffle_lanes!(4, u8x4, simd_shuffle4); + test_shuffle_lanes!(8, u8x8, simd_shuffle8); + test_shuffle_lanes!(16, u8x16, simd_shuffle16); + test_shuffle_lanes!(32, u8x32, simd_shuffle32); + test_shuffle_lanes!(64, u8x64, simd_shuffle64); + + extern "platform-intrinsic" { + fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; + } + let v = u8x2([0, 0]); + const I: [u32; 2] = [4, 4]; + unsafe { + let _: u8x2 = simd_shuffle(v, v, I); + //~^ ERROR invalid monomorphization of `simd_shuffle` intrinsic + } +} diff --git a/src/test/ui/simd/shuffle-not-out-of-bounds.stderr b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr new file mode 100644 index 000000000..415f04d93 --- /dev/null +++ b/src/test/ui/simd/shuffle-not-out-of-bounds.stderr @@ -0,0 +1,75 @@ +error[E0511]: invalid monomorphization of `simd_shuffle2` intrinsic: shuffle index #0 is out of bounds (limit 4) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(2, u8x2, simd_shuffle2); + | ------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle4` intrinsic: shuffle index #0 is out of bounds (limit 8) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(4, u8x4, simd_shuffle4); + | ------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle8` intrinsic: shuffle index #0 is out of bounds (limit 16) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(8, u8x8, simd_shuffle8); + | ------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle16` intrinsic: shuffle index #0 is out of bounds (limit 32) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(16, u8x16, simd_shuffle16); + | ---------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle32` intrinsic: shuffle index #0 is out of bounds (limit 64) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(32, u8x32, simd_shuffle32); + | ---------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle64` intrinsic: shuffle index #0 is out of bounds (limit 128) + --> $DIR/shuffle-not-out-of-bounds.rs:56:21 + | +LL | $y(vec1, vec2, ARR) + | ^^^^^^^^^^^^^^^^^^^ +... +LL | test_shuffle_lanes!(64, u8x64, simd_shuffle64); + | ---------------------------------------------- in this macro invocation + | + = note: this error originates in the macro `test_shuffle_lanes` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0511]: invalid monomorphization of `simd_shuffle` intrinsic: shuffle index #0 is out of bounds (limit 4) + --> $DIR/shuffle-not-out-of-bounds.rs:84:23 + | +LL | let _: u8x2 = simd_shuffle(v, v, I); + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + +For more information about this error, try `rustc --explain E0511`. diff --git a/src/test/ui/simd/shuffle.rs b/src/test/ui/simd/shuffle.rs new file mode 100644 index 000000000..3592adfdc --- /dev/null +++ b/src/test/ui/simd/shuffle.rs @@ -0,0 +1,24 @@ +//run-pass +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_shuffle<T, I, U>(a: T, b: T, i: I) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd<T, const N: usize>([T; N]); + +fn main() { + const I1: [u32; 4] = [0, 2, 4, 6]; + const I2: [u32; 2] = [1, 5]; + let a = Simd::<u8, 4>([0, 1, 2, 3]); + let b = Simd::<u8, 4>([4, 5, 6, 7]); + unsafe { + let x: Simd<u8, 4> = simd_shuffle(a, b, I1); + assert_eq!(x.0, [0, 2, 4, 6]); + + let y: Simd<u8, 2> = simd_shuffle(a, b, I2); + assert_eq!(y.0, [1, 5]); + } +} diff --git a/src/test/ui/simd/simd-bitmask.rs b/src/test/ui/simd/simd-bitmask.rs new file mode 100644 index 000000000..14ee2e741 --- /dev/null +++ b/src/test/ui/simd/simd-bitmask.rs @@ -0,0 +1,52 @@ +//run-pass +//ignore-endian-big behavior of simd_select_bitmask is endian-specific +#![feature(repr_simd, platform_intrinsics)] + +extern "platform-intrinsic" { + fn simd_bitmask<T, U>(v: T) -> U; + fn simd_select_bitmask<T, U>(m: T, a: U, b: U) -> U; +} + +#[derive(Copy, Clone)] +#[repr(simd)] +struct Simd<T, const N: usize>([T; N]); + +fn main() { + unsafe { + let v = Simd::<i8, 4>([-1, 0, -1, 0]); + let i: u8 = simd_bitmask(v); + let a: [u8; 1] = simd_bitmask(v); + + assert_eq!(i, 0b0101); + assert_eq!(a, [0b0101]); + + let v = Simd::<i8, 16>([0, 0, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0]); + let i: u16 = simd_bitmask(v); + let a: [u8; 2] = simd_bitmask(v); + + assert_eq!(i, 0b0101000000001100); + assert_eq!(a, [0b1100, 0b01010000]); + } + + unsafe { + let a = Simd::<i32, 8>([0, 1, 2, 3, 4, 5, 6, 7]); + let b = Simd::<i32, 8>([8, 9, 10, 11, 12, 13, 14, 15]); + let e = [0, 9, 2, 11, 12, 13, 14, 15]; + + let r = simd_select_bitmask(0b0101u8, a, b); + assert_eq!(r.0, e); + + let r = simd_select_bitmask([0b0101u8], a, b); + assert_eq!(r.0, e); + + let a = Simd::<i32, 16>([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); + let b = Simd::<i32, 16>([16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]); + let e = [16, 17, 2, 3, 20, 21, 22, 23, 24, 25, 26, 27, 12, 29, 14, 31]; + + let r = simd_select_bitmask(0b0101000000001100u16, a, b); + assert_eq!(r.0, e); + + let r = simd_select_bitmask([0b1100u8, 0b01010000u8], a, b); + assert_eq!(r.0, e); + } +} diff --git a/src/test/ui/simd/size-align.rs b/src/test/ui/simd/size-align.rs new file mode 100644 index 000000000..0afa49472 --- /dev/null +++ b/src/test/ui/simd/size-align.rs @@ -0,0 +1,53 @@ +// 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<T>` properly +/// Please consult the issue #20460 +fn check<T>() { + assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); + assert_eq!(mem::size_of::<T>() % mem::min_align_of::<T>(), 0); +} + +#[repr(simd)] +struct U8<const N: usize>([u8; N]); + +#[repr(simd)] +struct I16<const N: usize>([i16; N]); + +#[repr(simd)] +struct F32<const N: usize>([f32; N]); + +#[repr(simd)] +struct Usize<const N: usize>([usize; N]); + +#[repr(simd)] +struct Isize<const N: usize>([isize; N]); + +fn main() { + check::<U8<2>>(); + check::<U8<4>>(); + check::<U8<8>>(); + + check::<I16<2>>(); + check::<I16<4>>(); + check::<I16<8>>(); + + check::<F32<2>>(); + check::<F32<4>>(); + check::<F32<8>>(); + + check::<Usize<2>>(); + check::<Usize<4>>(); + check::<Usize<8>>(); + + check::<Isize<2>>(); + check::<Isize<4>>(); + check::<Isize<8>>(); +} diff --git a/src/test/ui/simd/target-feature-mixup.rs b/src/test/ui/simd/target-feature-mixup.rs new file mode 100644 index 000000000..6d7688191 --- /dev/null +++ b/src/test/ui/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/type-generic-monomorphisation-empty.rs b/src/test/ui/simd/type-generic-monomorphisation-empty.rs new file mode 100644 index 000000000..2bf6641e9 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-empty.rs @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd<0>` of zero length + +#[repr(simd)] +struct Simd<const N: usize>([f32; N]); + +fn main() { + let _ = Simd::<0>([]); +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-empty.stderr b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr new file mode 100644 index 000000000..b334b1f4b --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-empty.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd<0>` of zero length + +error: aborting due to previous error + diff --git a/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs b/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs new file mode 100644 index 000000000..ae321c974 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-extern-nonnull-ptr.rs @@ -0,0 +1,23 @@ +// run-pass +// ignore-emscripten + +#![feature(extern_types)] +#![feature(repr_simd)] + +use std::ptr::NonNull; + +extern { + type Extern; +} + +#[repr(simd)] +struct S<T>(T); + +#[inline(never)] +fn identity<T>(v: T) -> T { + v +} + +fn main() { + let _v: S<[Option<NonNull<Extern>>; 4]> = identity(S([None; 4])); +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs b/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs new file mode 100644 index 000000000..0bc73b155 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-non-primitive.rs @@ -0,0 +1,14 @@ +// build-fail + +#![feature(repr_simd)] + +struct E; + +// error-pattern:monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E` + +#[repr(simd)] +struct S<T>([T; 4]); + +fn main() { + let _v: Option<S<E>> = None; +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr b/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr new file mode 100644 index 000000000..9e8f06b82 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-non-primitive.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S<E>` with a non-primitive-scalar (integer/float/pointer) element type `E` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.rs b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs new file mode 100644 index 000000000..a7dc482f3 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.rs @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + +// error-pattern:monomorphising SIMD type `Simd<65536>` of length greater than 32768 + +#[repr(simd)] +struct Simd<const N: usize>([f32; N]); + +fn main() { + let _ = Simd::<65536>([0.; 65536]); +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr new file mode 100644 index 000000000..a2dba1222 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-oversized.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd<65536>` of length greater than 32768 + +error: aborting due to previous error + diff --git a/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs b/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs new file mode 100644 index 000000000..9b645d363 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-power-of-two.rs @@ -0,0 +1,10 @@ +// run-pass + +#![feature(repr_simd, platform_intrinsics)] + +#[repr(simd)] +struct Simd<const N: usize>([f32; N]); + +fn main() { + let _ = Simd::<3>([0.; 3]); +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs b/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs new file mode 100644 index 000000000..3e02b08ce --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.rs @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd)] + +// error-pattern:monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +#[repr(simd)] +struct S<T>(T); + +fn main() { + let _v: Option<S<[*mut [u8]; 4]>> = None; +} diff --git a/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr b/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr new file mode 100644 index 000000000..3888e7a0f --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation-wide-ptr.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S<[*mut [u8]; 4]>` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/type-generic-monomorphisation.rs b/src/test/ui/simd/type-generic-monomorphisation.rs new file mode 100644 index 000000000..12f9d65d7 --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation.rs @@ -0,0 +1,14 @@ +// build-fail + +#![feature(repr_simd, platform_intrinsics)] + + +// error-pattern:monomorphising SIMD type `Simd2<X>` with a non-primitive-scalar (integer/float/pointer) element type `X` + +struct X(Vec<i32>); +#[repr(simd)] +struct Simd2<T>(T, T); + +fn main() { + let _ = Simd2(X(vec![]), X(vec![])); +} diff --git a/src/test/ui/simd/type-generic-monomorphisation.stderr b/src/test/ui/simd/type-generic-monomorphisation.stderr new file mode 100644 index 000000000..7f23893ac --- /dev/null +++ b/src/test/ui/simd/type-generic-monomorphisation.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `Simd2<X>` with a non-primitive-scalar (integer/float/pointer) element type `X` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/type-len.rs b/src/test/ui/simd/type-len.rs new file mode 100644 index 000000000..d82c70b8d --- /dev/null +++ b/src/test/ui/simd/type-len.rs @@ -0,0 +1,39 @@ +#![feature(repr_simd)] +#![allow(non_camel_case_types)] + + +#[repr(simd)] +struct empty; //~ ERROR SIMD vector cannot be empty + +#[repr(simd)] +struct empty2([f32; 0]); //~ ERROR SIMD vector cannot be empty + +#[repr(simd)] +struct pow2([f32; 7]); + +#[repr(simd)] +struct i64f64(i64, f64); //~ ERROR SIMD vector should be homogeneous + +struct Foo; + +#[repr(simd)] +struct FooV(Foo, Foo); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct FooV2([Foo; 2]); //~ ERROR SIMD vector element type should be a primitive scalar (integer/float/pointer) type + +#[repr(simd)] +struct TooBig([f32; 65536]); //~ ERROR SIMD vector cannot have more than 32768 elements + +#[repr(simd)] +struct JustRight([u128; 32768]); + +#[repr(simd)] +struct RGBA { + r: f32, + g: f32, + b: f32, + a: f32 +} + +fn main() {} diff --git a/src/test/ui/simd/type-len.stderr b/src/test/ui/simd/type-len.stderr new file mode 100644 index 000000000..2a6bd1b0f --- /dev/null +++ b/src/test/ui/simd/type-len.stderr @@ -0,0 +1,40 @@ +error[E0075]: SIMD vector cannot be empty + --> $DIR/type-len.rs:6:1 + | +LL | struct empty; + | ^^^^^^^^^^^^ + +error[E0075]: SIMD vector cannot be empty + --> $DIR/type-len.rs:9:1 + | +LL | struct empty2([f32; 0]); + | ^^^^^^^^^^^^^ + +error[E0076]: SIMD vector should be homogeneous + --> $DIR/type-len.rs:15:1 + | +LL | struct i64f64(i64, f64); + | ^^^^^^^^^^^^^ SIMD elements must have the same type + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/type-len.rs:20:1 + | +LL | struct FooV(Foo, Foo); + | ^^^^^^^^^^^ + +error[E0077]: SIMD vector element type should be a primitive scalar (integer/float/pointer) type + --> $DIR/type-len.rs:23:1 + | +LL | struct FooV2([Foo; 2]); + | ^^^^^^^^^^^^ + +error[E0075]: SIMD vector cannot have more than 32768 elements + --> $DIR/type-len.rs:26:1 + | +LL | struct TooBig([f32; 65536]); + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0075, E0076, E0077. +For more information about an error, try `rustc --explain E0075`. diff --git a/src/test/ui/simd/type-wide-ptr.rs b/src/test/ui/simd/type-wide-ptr.rs new file mode 100644 index 000000000..88f62a07e --- /dev/null +++ b/src/test/ui/simd/type-wide-ptr.rs @@ -0,0 +1,12 @@ +// build-fail + +#![feature(repr_simd)] + +// error-pattern:monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +#[repr(simd)] +struct S([*mut [u8]; 4]); + +fn main() { + let _v: Option<S> = None; +} diff --git a/src/test/ui/simd/type-wide-ptr.stderr b/src/test/ui/simd/type-wide-ptr.stderr new file mode 100644 index 000000000..51d3c0050 --- /dev/null +++ b/src/test/ui/simd/type-wide-ptr.stderr @@ -0,0 +1,4 @@ +error: monomorphising SIMD type `S` with a non-primitive-scalar (integer/float/pointer) element type `*mut [u8]` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/wasm-simd-indirect.rs b/src/test/ui/simd/wasm-simd-indirect.rs new file mode 100644 index 000000000..88f92fce2 --- /dev/null +++ b/src/test/ui/simd/wasm-simd-indirect.rs @@ -0,0 +1,31 @@ +// build-pass + +#[cfg(target_arch = "wasm32")] +fn main() { + unsafe { + a::api_with_simd_feature(); + } +} + +#[cfg(target_arch = "wasm32")] +mod a { + use std::arch::wasm32::*; + + #[target_feature(enable = "simd128")] + pub unsafe fn api_with_simd_feature() { + crate::b::api_takes_v128(u64x2(0, 1)); + } +} + +#[cfg(target_arch = "wasm32")] +mod b { + use std::arch::wasm32::*; + + #[inline(never)] + pub fn api_takes_v128(a: v128) -> v128 { + a + } +} + +#[cfg(not(target_arch = "wasm32"))] +fn main() {} |