about summary refs log tree commit diff
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.rs121
1 files changed, 121 insertions, 0 deletions
diff --git a/tests/ui/simd/intrinsic/generic-cast-pass.rs b/tests/ui/simd/intrinsic/generic-cast-pass.rs
new file mode 100644
index 00000000000..15f232e2c0f
--- /dev/null
+++ b/tests/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)
+}