Skip to content

Commit 778457c

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

20 files changed

+816
-585
lines changed

tests/auxiliary/minisimd.rs

Lines changed: 56 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
#![allow(unexpected_cfgs)]
14+
15+
#[cfg_attr(minisimd_const, path = "minisimd_const_impls.rs")]
16+
#[cfg_attr(not(minisimd_const), path = "minisimd_impls.rs")]
17+
mod impls;
1318

1419
// The field is currently left `pub` for convenience in porting tests, many of
1520
// which attempt to just construct it directly. That still works; it's just the
@@ -24,39 +29,32 @@ impl<T: Copy, const N: usize> Clone for Simd<T, N> {
2429
}
2530
}
2631

27-
impl<T: PartialEq, const N: usize> PartialEq for Simd<T, N> {
28-
fn eq(&self, other: &Self) -> bool {
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3332
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for Simd<T, N> {
3433
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
3534
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
3635
}
3736
}
3837

39-
impl<T, const N: usize> 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-
4638
impl<T, const N: usize> Simd<T, N> {
4739
pub const fn from_array(a: [T; N]) -> Self {
4840
Simd(a)
4941
}
50-
pub fn as_array(&self) -> &[T; N] {
42+
pub const fn as_array(&self) -> &[T; N] {
5143
let p: *const Self = self;
5244
unsafe { &*p.cast::<[T; N]>() }
5345
}
54-
pub fn into_array(self) -> [T; N]
46+
pub const fn into_array(self) -> [T; N]
5547
where
5648
T: Copy,
5749
{
5850
*self.as_array()
5951
}
52+
pub const fn splat(a: T) -> Self
53+
where
54+
T: Copy,
55+
{
56+
Self([a; N])
57+
}
6058
}
6159

6260
pub type u8x2 = Simd<u8, 2>;
@@ -109,6 +107,14 @@ pub type i64x8 = Simd<i64, 8>;
109107
pub type i128x2 = Simd<i128, 2>;
110108
pub type i128x4 = Simd<i128, 4>;
111109

110+
pub type usizex2 = Simd<usize, 2>;
111+
pub type usizex4 = Simd<usize, 4>;
112+
pub type usizex8 = Simd<usize, 8>;
113+
114+
pub type isizex2 = Simd<isize, 2>;
115+
pub type isizex4 = Simd<isize, 4>;
116+
pub type isizex8 = Simd<isize, 8>;
117+
112118
pub type f32x2 = Simd<f32, 2>;
113119
pub type f32x4 = Simd<f32, 4>;
114120
pub type f32x8 = Simd<f32, 8>;
@@ -122,7 +128,7 @@ pub type f64x8 = Simd<f64, 8>;
122128
// which attempt to just construct it directly. That still works; it's just the
123129
// `.0` projection that doesn't.
124130
#[repr(simd, packed)]
125-
#[derive(Copy)]
131+
#[derive(Copy, Eq)]
126132
pub struct PackedSimd<T, const N: usize>(pub [T; N]);
127133

128134
impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
@@ -131,12 +137,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131137
}
132138
}
133139

134-
impl<T: PartialEq, const N: usize> PartialEq for PackedSimd<T, N> {
135-
fn eq(&self, other: &Self) -> bool {
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140140
impl<T: core::fmt::Debug, const N: usize> core::fmt::Debug for PackedSimd<T, N> {
141141
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
142142
<[T; N] as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +147,46 @@ impl<T, const N: usize> PackedSimd<T, N> {
147147
pub const fn from_array(a: [T; N]) -> Self {
148148
PackedSimd(a)
149149
}
150-
pub fn as_array(&self) -> &[T; N] {
150+
pub const fn as_array(&self) -> &[T; N] {
151151
let p: *const Self = self;
152152
unsafe { &*p.cast::<[T; N]>() }
153153
}
154-
pub fn into_array(self) -> [T; N]
154+
pub const fn into_array(self) -> [T; N]
155155
where
156156
T: Copy,
157157
{
158158
*self.as_array()
159159
}
160+
pub const fn splat(a: T) -> Self
161+
where
162+
T: Copy,
163+
{
164+
Self([a; N])
165+
}
160166
}
167+
168+
/// Version of `assert_eq` that ignores fancy runtime printing in const context
169+
#[cfg(minisimd_const)]
170+
#[macro_export]
171+
macro_rules! assert_eq_const_safe {
172+
($left:expr, $right:expr $(,)?) => {
173+
assert_eq_const_safe!(
174+
$left,
175+
$right,
176+
concat!("`", stringify!($left), "` == `", stringify!($right), "`")
177+
);
178+
};
179+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
180+
{
181+
let left = $left;
182+
let right = $right;
183+
// type inference works better with the concrete type on the
184+
// left, but humans work better with the expected on the
185+
// right
186+
assert!(right == left, $($($arg)*),*);
187+
}
188+
};
189+
}
190+
191+
#[cfg(minisimd_const)]
192+
use assert_eq_const_safe;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use super::*;
2+
3+
impl<T: [const] PartialEq, const N: usize> const PartialEq for Simd<T, N> {
4+
fn eq(&self, other: &Self) -> bool {
5+
self.as_array() == other.as_array()
6+
}
7+
}
8+
9+
impl<T, const N: usize> const core::ops::Index<usize> for Simd<T, N> {
10+
type Output = T;
11+
fn index(&self, i: usize) -> &T {
12+
&self.as_array()[i]
13+
}
14+
}
15+
16+
impl<T: [const] PartialEq, const N: usize> const PartialEq for PackedSimd<T, N> {
17+
fn eq(&self, other: &Self) -> bool {
18+
self.as_array() == other.as_array()
19+
}
20+
}

tests/auxiliary/minisimd_impls.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
use super::*;
2+
3+
impl<T: PartialEq, const N: usize> PartialEq for Simd<T, N> {
4+
fn eq(&self, other: &Self) -> bool {
5+
self.as_array() == other.as_array()
6+
}
7+
}
8+
9+
impl<T, const N: usize> core::ops::Index<usize> for Simd<T, N> {
10+
type Output = T;
11+
fn index(&self, i: usize) -> &T {
12+
&self.as_array()[i]
13+
}
14+
}
15+
16+
impl<T: PartialEq, const N: usize> PartialEq for PackedSimd<T, N> {
17+
fn eq(&self, other: &Self) -> bool {
18+
self.as_array() == other.as_array()
19+
}
20+
}

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

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
//@ run-pass
22
//@ ignore-emscripten
33
//@ ignore-android
4+
//@ compile-flags: --cfg minisimd_const
45

56
// FIXME: this test fails on arm-android because the NDK version 14 is too old.
67
// It needs at least version 18. We disable it on all android build bots because
78
// there is no way in compile-test to disable it for an (arch,os) pair.
89

910
// Test that the simd floating-point math intrinsics produce correct results.
1011

11-
#![feature(repr_simd, intrinsics, core_intrinsics)]
12+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
1213
#![allow(non_camel_case_types)]
1314

1415
#[path = "../../../auxiliary/minisimd.rs"]
@@ -34,7 +35,7 @@ macro_rules! assert_approx_eq {
3435
}};
3536
}
3637

37-
fn main() {
38+
const fn abs_and_rounding() {
3839
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
3940
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4041
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
@@ -43,8 +44,33 @@ fn main() {
4344

4445
unsafe {
4546
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
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+
fn math_functions() {
68+
let x = f32x4::from_array([1.0, 1.0, 1.0, 1.0]);
69+
let z = f32x4::from_array([0.0, 0.0, 0.0, 0.0]);
4770

71+
let h = f32x4::from_array([0.5, 0.5, 0.5, 0.5]);
72+
73+
unsafe {
4874
let r = simd_fcos(z);
4975
assert_approx_eq!(x, r);
5076

@@ -74,21 +100,11 @@ fn main() {
74100

75101
let r = simd_fsin(z);
76102
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);
93103
}
94104
}
105+
106+
fn main() {
107+
const { abs_and_rounding() };
108+
abs_and_rounding();
109+
math_functions();
110+
}
Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
// Test that the simd_f{min,max} intrinsics produce the correct results.
56

6-
#![feature(repr_simd, core_intrinsics)]
7+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
78
#![allow(non_camel_case_types)]
89

910
#[path = "../../../auxiliary/minisimd.rs"]
@@ -12,7 +13,7 @@ use minisimd::*;
1213

1314
use std::intrinsics::simd::*;
1415

15-
fn main() {
16+
const fn minmax() {
1617
let x = f32x4::from_array([1.0, 2.0, 3.0, 4.0]);
1718
let y = f32x4::from_array([2.0, 1.0, 4.0, 3.0]);
1819

@@ -28,22 +29,27 @@ fn main() {
2829
unsafe {
2930
let min0 = simd_fmin(x, y);
3031
let min1 = simd_fmin(y, x);
31-
assert_eq!(min0, min1);
32+
assert_eq_const_safe!(min0, min1);
3233
let e = f32x4::from_array([1.0, 1.0, 3.0, 3.0]);
33-
assert_eq!(min0, e);
34+
assert_eq_const_safe!(min0, e);
3435
let minn = simd_fmin(x, n);
35-
assert_eq!(minn, x);
36+
assert_eq_const_safe!(minn, x);
3637
let minn = simd_fmin(y, n);
37-
assert_eq!(minn, y);
38+
assert_eq_const_safe!(minn, y);
3839

3940
let max0 = simd_fmax(x, y);
4041
let max1 = simd_fmax(y, x);
41-
assert_eq!(max0, max1);
42+
assert_eq_const_safe!(max0, max1);
4243
let e = f32x4::from_array([2.0, 2.0, 4.0, 4.0]);
43-
assert_eq!(max0, e);
44+
assert_eq_const_safe!(max0, e);
4445
let maxn = simd_fmax(x, n);
45-
assert_eq!(maxn, x);
46+
assert_eq_const_safe!(maxn, x);
4647
let maxn = simd_fmax(y, n);
47-
assert_eq!(maxn, y);
48+
assert_eq_const_safe!(maxn, y);
4849
}
4950
}
51+
52+
fn main() {
53+
const { minmax() };
54+
minmax();
55+
}

0 commit comments

Comments
 (0)