|
1 | 1 | // run-pass |
2 | | -#![allow(unused_must_use)] |
3 | 2 | // ignore-emscripten FIXME(#45351) hits an LLVM assert |
4 | 3 |
|
5 | | -#![feature(repr_simd, platform_intrinsics, concat_idents, test)] |
6 | | -#![allow(non_camel_case_types)] |
7 | | - |
8 | | -extern crate test; |
9 | | - |
10 | | -#[repr(simd)] |
11 | | -#[derive(PartialEq, Debug)] |
12 | | -struct i32x4(i32, i32, i32, i32); |
13 | | -#[repr(simd)] |
14 | | -#[derive(PartialEq, Debug)] |
15 | | -struct i8x4(i8, i8, i8, i8); |
16 | | - |
17 | | -#[repr(simd)] |
18 | | -#[derive(PartialEq, Debug)] |
19 | | -struct u32x4(u32, u32, u32, u32); |
20 | | -#[repr(simd)] |
21 | | -#[derive(PartialEq, Debug)] |
22 | | -struct u8x4(u8, u8, u8, u8); |
23 | | - |
24 | | -#[repr(simd)] |
25 | | -#[derive(PartialEq, Debug)] |
26 | | -struct f32x4(f32, f32, f32, f32); |
27 | | - |
28 | | -#[repr(simd)] |
29 | | -#[derive(PartialEq, Debug)] |
30 | | -struct f64x4(f64, f64, f64, f64); |
31 | | - |
| 4 | +#![feature(repr_simd, platform_intrinsics)] |
32 | 5 |
|
33 | 6 | extern "platform-intrinsic" { |
34 | 7 | fn simd_cast<T, U>(x: T) -> U; |
35 | 8 | } |
36 | 9 |
|
37 | | -const A: i32 = -1234567; |
38 | | -const B: i32 = 12345678; |
39 | | -const C: i32 = -123456789; |
40 | | -const D: i32 = 1234567890; |
| 10 | +use std::cmp::{max, min}; |
41 | 11 |
|
42 | | -trait Foo { |
43 | | - fn is_float() -> bool { false } |
44 | | - fn in_range(x: i32) -> bool; |
45 | | -} |
46 | | -impl Foo for i32 { |
47 | | - fn in_range(_: i32) -> bool { true } |
48 | | -} |
49 | | -impl Foo for i8 { |
50 | | - fn in_range(x: i32) -> bool { -128 <= x && x < 128 } |
51 | | -} |
52 | | -impl Foo for u32 { |
53 | | - fn in_range(x: i32) -> bool { 0 <= x } |
54 | | -} |
55 | | -impl Foo for u8 { |
56 | | - fn in_range(x: i32) -> bool { 0 <= x && x < 128 } |
57 | | -} |
58 | | -impl Foo for f32 { |
59 | | - fn is_float() -> bool { true } |
60 | | - fn in_range(_: i32) -> bool { true } |
61 | | -} |
62 | | -impl Foo for f64 { |
63 | | - fn is_float() -> bool { true } |
64 | | - fn in_range(_: i32) -> bool { true } |
65 | | -} |
| 12 | +#[derive(Copy, Clone)] |
| 13 | +#[repr(simd)] |
| 14 | +struct V<T>([T; 2]); |
66 | 15 |
|
67 | 16 | fn main() { |
68 | | - macro_rules! test { |
69 | | - ($from: ident, $to: ident) => {{ |
70 | | - // force the casts to actually happen, or else LLVM/rustc |
71 | | - // may fold them and get slightly different results. |
72 | | - let (a, b, c, d) = test::black_box((A as $from, B as $from, C as $from, D as $from)); |
73 | | - // the SIMD vectors are all FOOx4, so we can concat_idents |
74 | | - // so we don't have to pass in the extra args to the macro |
75 | | - let mut from = simd_cast(concat_idents!($from, x4)(a, b, c, d)); |
76 | | - let mut to = concat_idents!($to, x4)(a as $to, |
77 | | - b as $to, |
78 | | - c as $to, |
79 | | - d as $to); |
80 | | - // assist type inference, it needs to know what `from` is |
81 | | - // for the `if` statements. |
82 | | - to == from; |
| 17 | + unsafe { |
| 18 | + let u = V::<u32>([i16::MIN as u32, i16::MAX as u32]); |
| 19 | + let i: V<i16> = simd_cast(u); |
| 20 | + assert_eq!(i.0[0], u.0[0] as i16); |
| 21 | + assert_eq!(i.0[1], u.0[1] as i16); |
| 22 | + } |
83 | 23 |
|
84 | | - // there are platform differences for some out of range |
85 | | - // casts, so we just normalize such things: it's OK for |
86 | | - // "invalid" calculations to result in nonsense answers. |
87 | | - // (e.g., negative float to unsigned integer goes through a |
88 | | - // library routine on the default i686 platforms, and the |
89 | | - // implementation of that routine differs on e.g., Linux |
90 | | - // vs. macOS, resulting in different answers.) |
91 | | - if $from::is_float() { |
92 | | - if !$to::in_range(A) { from.0 = 0 as $to; to.0 = 0 as $to; } |
93 | | - if !$to::in_range(B) { from.1 = 0 as $to; to.1 = 0 as $to; } |
94 | | - if !$to::in_range(C) { from.2 = 0 as $to; to.2 = 0 as $to; } |
95 | | - if !$to::in_range(D) { from.3 = 0 as $to; to.3 = 0 as $to; } |
96 | | - } |
| 24 | + unsafe { |
| 25 | + let f = V::<f32>([i16::MIN as f32, i16::MAX as f32]); |
| 26 | + let i: V<i16> = simd_cast(f); |
| 27 | + assert_eq!(i.0[0], f.0[0] as i16); |
| 28 | + assert_eq!(i.0[1], f.0[1] as i16); |
| 29 | + } |
97 | 30 |
|
98 | | - assert!(to == from, |
99 | | - "{} -> {} ({:?} != {:?})", stringify!($from), stringify!($to), |
100 | | - from, to); |
101 | | - }} |
| 31 | + unsafe { |
| 32 | + let f = V::<f32>([u8::MIN as f32, u8::MAX as f32]); |
| 33 | + let u: V<u8> = simd_cast(f); |
| 34 | + assert_eq!(u.0[0], f.0[0] as u8); |
| 35 | + assert_eq!(u.0[1], f.0[1] as u8); |
102 | 36 | } |
103 | | - macro_rules! tests { |
104 | | - (: $($to: ident),*) => { () }; |
105 | | - // repeating the list twice is easier than writing a cartesian |
106 | | - // product macro |
107 | | - ($from: ident $(, $from_: ident)*: $($to: ident),*) => { |
108 | | - fn $from() { unsafe { $( test!($from, $to); )* } } |
109 | | - tests!($($from_),*: $($to),*) |
110 | | - }; |
111 | | - ($($types: ident),*) => {{ |
112 | | - tests!($($types),* : $($types),*); |
113 | | - $($types();)* |
114 | | - }} |
| 37 | + |
| 38 | + unsafe { |
| 39 | + // We would like to do isize::MIN..=isize::MAX, but those values are not representable in |
| 40 | + // an f64, so we clamp to the range of an i32 to prevent running into UB. |
| 41 | + let f = V::<f64>([ |
| 42 | + max(isize::MIN, i32::MIN as isize) as f64, |
| 43 | + min(isize::MAX, i32::MAX as isize) as f64, |
| 44 | + ]); |
| 45 | + let i: V<isize> = simd_cast(f); |
| 46 | + assert_eq!(i.0[0], f.0[0] as isize); |
| 47 | + assert_eq!(i.0[1], f.0[1] as isize); |
115 | 48 | } |
116 | 49 |
|
117 | | - // test various combinations, including truncation, |
118 | | - // signed/unsigned extension, and floating point casts. |
119 | | - tests!(i32, i8, u32, u8, f32); |
120 | | - tests!(i32, u32, f32, f64) |
| 50 | + unsafe { |
| 51 | + let f = V::<f64>([ |
| 52 | + max(usize::MIN, u32::MIN as usize) as f64, |
| 53 | + min(usize::MAX, u32::MAX as usize) as f64, |
| 54 | + ]); |
| 55 | + let u: V<usize> = simd_cast(f); |
| 56 | + assert_eq!(u.0[0], f.0[0] as usize); |
| 57 | + assert_eq!(u.0[1], f.0[1] as usize); |
| 58 | + } |
121 | 59 | } |
0 commit comments