|
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