mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 13:04:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			122 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			122 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| // 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)
 | |
| }
 | 
