summaryrefslogtreecommitdiffstats
path: root/tests/ui/simd/intrinsic/generic-cast-pass.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/simd/intrinsic/generic-cast-pass.rs')
-rw-r--r--tests/ui/simd/intrinsic/generic-cast-pass.rs146
1 files changed, 42 insertions, 104 deletions
diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs
index 15f232e2c..89436c83e 100644
--- a/tests/ui/simd/intrinsic/generic-cast-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-cast-pass.rs
@@ -1,121 +1,59 @@
// 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);
-
+#![feature(repr_simd, platform_intrinsics)]
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;
+use std::cmp::{max, min};
-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 }
-}
+#[derive(Copy, Clone)]
+#[repr(simd)]
+struct V<T>([T; 2]);
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;
+ unsafe {
+ let u = V::<u32>([i16::MIN as u32, i16::MAX as u32]);
+ let i: V<i16> = simd_cast(u);
+ assert_eq!(i.0[0], u.0[0] as i16);
+ assert_eq!(i.0[1], u.0[1] as i16);
+ }
- // 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; }
- }
+ unsafe {
+ let f = V::<f32>([i16::MIN as f32, i16::MAX as f32]);
+ let i: V<i16> = simd_cast(f);
+ assert_eq!(i.0[0], f.0[0] as i16);
+ assert_eq!(i.0[1], f.0[1] as i16);
+ }
- assert!(to == from,
- "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to),
- from, to);
- }}
+ unsafe {
+ let f = V::<f32>([u8::MIN as f32, u8::MAX as f32]);
+ let u: V<u8> = simd_cast(f);
+ assert_eq!(u.0[0], f.0[0] as u8);
+ assert_eq!(u.0[1], f.0[1] as u8);
}
- 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();)*
- }}
+
+ unsafe {
+ // We would like to do isize::MIN..=isize::MAX, but those values are not representable in
+ // an f64, so we clamp to the range of an i32 to prevent running into UB.
+ let f = V::<f64>([
+ max(isize::MIN, i32::MIN as isize) as f64,
+ min(isize::MAX, i32::MAX as isize) as f64,
+ ]);
+ let i: V<isize> = simd_cast(f);
+ assert_eq!(i.0[0], f.0[0] as isize);
+ assert_eq!(i.0[1], f.0[1] as isize);
}
- // test various combinations, including truncation,
- // signed/unsigned extension, and floating point casts.
- tests!(i32, i8, u32, u8, f32);
- tests!(i32, u32, f32, f64)
+ unsafe {
+ let f = V::<f64>([
+ max(usize::MIN, u32::MIN as usize) as f64,
+ min(usize::MAX, u32::MAX as usize) as f64,
+ ]);
+ let u: V<usize> = simd_cast(f);
+ assert_eq!(u.0[0], f.0[0] as usize);
+ assert_eq!(u.0[1], f.0[1] as usize);
+ }
}