Skip to content

Commit 927e572

Browse files
committed
Enable const-testing for the ported SIMD intrinsics
1 parent f1d8fdb commit 927e572

18 files changed

+1335
-983
lines changed
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//! Auxiliary crate for tests that need SIMD types with *const trait impls*
2+
//!
3+
//! Historically the tests just made their own, but projections into simd types
4+
//! was banned by <https://github.com/rust-lang/compiler-team/issues/838>, which
5+
//! breaks `derive(Clone)`, so this exists to give easily-usable types that can
6+
//! be used without copy-pasting the definitions of the helpers everywhere.
7+
//!
8+
//! This makes no attempt to guard against ICEs. Using it with proper types
9+
//! and such is your responsibility in the tests you write.
10+
11+
#![allow(unused)]
12+
#![allow(non_camel_case_types)]
13+
14+
// The field is currently left `pub` for convenience in porting tests, many of
15+
// which attempt to just construct it directly. That still works; it's just the
16+
// `.0` projection that doesn't.
17+
#[repr(simd)]
18+
#[derive(Copy, Eq)]
19+
pub struct Simd<T, const N: usize>(pub [T; N]);
20+
21+
impl<T: Copy, const N: usize> Clone for Simd<T, N> {
22+
fn clone(&self) -> Self {
23+
*self
24+
}
25+
}
26+
27+
impl<T: [const] PartialEq, const N: usize> const PartialEq for Simd<T, N> {
28+
fn eq(&self, other: &Self) -> bool {
29+
self.as_array() == other.as_array()
30+
}
31+
}
32+
33+
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
34+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
35+
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
36+
}
37+
}
38+
39+
impl<T, const N: usize> const core::ops::Index<usize> for Simd<T, N> {
40+
type Output = T;
41+
fn index(&self, i: usize) -> &T {
42+
&self.as_array()[i]
43+
}
44+
}
45+
46+
impl<T, const N: usize> Simd<T, N> {
47+
pub const fn from_array(a: [T; N]) -> Self {
48+
Simd(a)
49+
}
50+
pub const fn as_array(&self) -> &[T; N] {
51+
let p: *const Self = self;
52+
unsafe { &*p.cast::<[T; N]>() }
53+
}
54+
pub const fn into_array(self) -> [T; N]
55+
where
56+
T: Copy,
57+
{
58+
*self.as_array()
59+
}
60+
pub const fn splat(a: T) -> Self
61+
where
62+
T: Copy,
63+
{
64+
Self([a; N])
65+
}
66+
}
67+
68+
pub type u8x2 = Simd<u8, 2>;
69+
pub type u8x4 = Simd<u8, 4>;
70+
pub type u8x8 = Simd<u8, 8>;
71+
pub type u8x16 = Simd<u8, 16>;
72+
pub type u8x32 = Simd<u8, 32>;
73+
pub type u8x64 = Simd<u8, 64>;
74+
75+
pub type u16x2 = Simd<u16, 2>;
76+
pub type u16x4 = Simd<u16, 4>;
77+
pub type u16x8 = Simd<u16, 8>;
78+
pub type u16x16 = Simd<u16, 16>;
79+
pub type u16x32 = Simd<u16, 32>;
80+
81+
pub type u32x2 = Simd<u32, 2>;
82+
pub type u32x4 = Simd<u32, 4>;
83+
pub type u32x8 = Simd<u32, 8>;
84+
pub type u32x16 = Simd<u32, 16>;
85+
86+
pub type u64x2 = Simd<u64, 2>;
87+
pub type u64x4 = Simd<u64, 4>;
88+
pub type u64x8 = Simd<u64, 8>;
89+
90+
pub type u128x2 = Simd<u128, 2>;
91+
pub type u128x4 = Simd<u128, 4>;
92+
93+
pub type i8x2 = Simd<i8, 2>;
94+
pub type i8x4 = Simd<i8, 4>;
95+
pub type i8x8 = Simd<i8, 8>;
96+
pub type i8x16 = Simd<i8, 16>;
97+
pub type i8x32 = Simd<i8, 32>;
98+
pub type i8x64 = Simd<i8, 64>;
99+
100+
pub type i16x2 = Simd<i16, 2>;
101+
pub type i16x4 = Simd<i16, 4>;
102+
pub type i16x8 = Simd<i16, 8>;
103+
pub type i16x16 = Simd<i16, 16>;
104+
pub type i16x32 = Simd<i16, 32>;
105+
106+
pub type i32x2 = Simd<i32, 2>;
107+
pub type i32x4 = Simd<i32, 4>;
108+
pub type i32x8 = Simd<i32, 8>;
109+
pub type i32x16 = Simd<i32, 16>;
110+
111+
pub type i64x2 = Simd<i64, 2>;
112+
pub type i64x4 = Simd<i64, 4>;
113+
pub type i64x8 = Simd<i64, 8>;
114+
115+
pub type i128x2 = Simd<i128, 2>;
116+
pub type i128x4 = Simd<i128, 4>;
117+
118+
pub type usizex2 = Simd<usize, 2>;
119+
pub type usizex4 = Simd<usize, 4>;
120+
pub type usizex8 = Simd<usize, 8>;
121+
122+
pub type isizex2 = Simd<isize, 2>;
123+
pub type isizex4 = Simd<isize, 4>;
124+
pub type isizex8 = Simd<isize, 8>;
125+
126+
pub type f32x2 = Simd<f32, 2>;
127+
pub type f32x4 = Simd<f32, 4>;
128+
pub type f32x8 = Simd<f32, 8>;
129+
pub type f32x16 = Simd<f32, 16>;
130+
131+
pub type f64x2 = Simd<f64, 2>;
132+
pub type f64x4 = Simd<f64, 4>;
133+
pub type f64x8 = Simd<f64, 8>;
134+
135+
// The field is currently left `pub` for convenience in porting tests, many of
136+
// which attempt to just construct it directly. That still works; it's just the
137+
// `.0` projection that doesn't.
138+
#[repr(simd, packed)]
139+
#[derive(Copy)]
140+
pub struct PackedSimd<T, const N: usize>(pub [T; N]);
141+
142+
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
143+
fn clone(&self) -> Self {
144+
*self
145+
}
146+
}
147+
148+
impl<T: [const] PartialEq, const N: usize> const PartialEq for PackedSimd<T, N> {
149+
fn eq(&self, other: &Self) -> bool {
150+
self.as_array() == other.as_array()
151+
}
152+
}
153+
154+
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
155+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
156+
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
157+
}
158+
}
159+
160+
impl<T, const N: usize> PackedSimd<T, N> {
161+
pub const fn from_array(a: [T; N]) -> Self {
162+
PackedSimd(a)
163+
}
164+
pub const fn as_array(&self) -> &[T; N] {
165+
let p: *const Self = self;
166+
unsafe { &*p.cast::<[T; N]>() }
167+
}
168+
pub const fn into_array(self) -> [T; N]
169+
where
170+
T: Copy,
171+
{
172+
*self.as_array()
173+
}
174+
pub const fn splat(a: T) -> Self
175+
where
176+
T: Copy,
177+
{
178+
Self([a; N])
179+
}
180+
}
181+
182+
/// Creates a function for runtime and a test for constant-time.
183+
#[macro_export]
184+
macro_rules! make_runtime_and_compiletime {
185+
($(
186+
$(#[$attr:meta])*
187+
fn $name:ident() $block:block
188+
)*) => {
189+
$(
190+
$(#[$attr])*
191+
fn $name() $block
192+
$(#[$attr])*
193+
const _: () = $block;
194+
)*
195+
}
196+
}
197+
198+
/// Version of `assert_eq` that ignores fancy runtime printing in const context
199+
#[macro_export]
200+
macro_rules! assert_eq_const_safe {
201+
($left:expr, $right:expr $(,)?) => {
202+
assert_eq_const_safe!(
203+
$left,
204+
$right,
205+
concat!("`", stringify!($left), "` == `", stringify!($right), "`")
206+
);
207+
};
208+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
209+
{
210+
let left = $left;
211+
let right = $right;
212+
// type inference works better with the concrete type on the
213+
// left, but humans work better with the expected on the
214+
// right
215+
assert!(right == left, $($($arg)*),*);
216+
}
217+
};
218+
}
219+
220+
use {assert_eq_const_safe, make_runtime_and_compiletime};

tests/ui/simd/intrinsic/float-math-pass.rs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@
88

99
// Test that the simd floating-point math intrinsics produce correct results.
1010

11-
#![feature(repr_simd, intrinsics, core_intrinsics)]
11+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
1212
#![allow(non_camel_case_types)]
1313

14-
#[path = "../../../auxiliary/minisimd.rs"]
15-
mod minisimd;
16-
use minisimd::*;
14+
#[path = "../auxiliary/minisimd_const.rs"]
15+
mod minisimd_const;
16+
use minisimd_const::*;
1717

1818
use std::intrinsics::simd::*;
1919

@@ -34,17 +34,44 @@ macro_rules! assert_approx_eq {
3434
}};
3535
}
3636

37-
fn main() {
37+
make_runtime_and_compiletime! {
38+
fn abs_and_rounding() {
39+
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
40+
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
41+
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
42+
43+
let h = f32x4::from_array([0.5, 0.5, 0.5, 0.5]);
44+
45+
unsafe {
46+
let r = simd_fabs(y);
47+
assert_eq_const_safe!(x, r);
48+
49+
// rounding functions
50+
let r = simd_floor(h);
51+
assert_eq_const_safe!(z, r);
52+
53+
let r = simd_ceil(h);
54+
assert_eq_const_safe!(x, r);
55+
56+
let r = simd_round(h);
57+
assert_eq_const_safe!(x, r);
58+
59+
let r = simd_round_ties_even(h);
60+
assert_eq_const_safe!(z, r);
61+
62+
let r = simd_trunc(h);
63+
assert_eq_const_safe!(z, r);
64+
}
65+
}
66+
}
67+
68+
fn math_functions() {
3869
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
39-
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4070
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
4171

4272
let h = f32x4::from_array([0.5, 0.5, 0.5, 0.5]);
4373

4474
unsafe {
45-
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
47-
4875
let r = simd_fcos(z);
4976
assert_approx_eq!(x, r);
5077

@@ -74,21 +101,10 @@ fn main() {
74101

75102
let r = simd_fsin(z);
76103
assert_approx_eq!(z, r);
77-
78-
// rounding functions
79-
let r = simd_floor(h);
80-
assert_eq!(z, r);
81-
82-
let r = simd_ceil(h);
83-
assert_eq!(x, r);
84-
85-
let r = simd_round(h);
86-
assert_eq!(x, r);
87-
88-
let r = simd_round_ties_even(h);
89-
assert_eq!(z, r);
90-
91-
let r = simd_trunc(h);
92-
assert_eq!(z, r);
93104
}
94105
}
106+
107+
fn main() {
108+
abs_and_rounding();
109+
math_functions();
110+
}

0 commit comments

Comments
 (0)