Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm · rust-lang/rust@714f1ce · GitHub
Skip to content

Commit 714f1ce

Browse files
authored
Rollup merge of #147521 - sayantn:simd-const-intrinsics, r=madsmtm
Make SIMD intrinsics available in `const`-contexts successor to #146568, this PR actually makes the SIMD intrinsics `const`, and modifies the tests to test the const-eval implementations r? `@tgross35` ig (although feel free to reassign, this is not anything targeted really)
2 parents 2cc5bf7 + 82ff614 commit 714f1ce

20 files changed

Lines changed: 490 additions & 337 deletions

‎library/core/src/intrinsics/simd.rs‎

Lines changed: 59 additions & 58 deletions
Large diffs are not rendered by default.

‎src/tools/miri/tests/pass/intrinsics/portable-simd.rs‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl<T: Copy, const N: usize> PackedSimd<T, N> {
6060

6161
#[rustc_intrinsic]
6262
#[rustc_nounwind]
63-
pubunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
63+
pubconstunsafefnsimd_shuffle_const_generic<T,U,constIDX:&'static[u32]>(x:T,y:T) -> U;
6464

6565
fnsimd_ops_f16(){
6666
use intrinsics::*;

‎tests/auxiliary/minisimd.rs‎

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
1111
#![allow(unused)]
1212
#![allow(non_camel_case_types)]
13+
// FIXME: `cfg(minisimd_const)` is used to toggle use of const trait impls, which require a few
14+
// nightly features. Remove this when `const_trait_impls`, `const_cmp` and `const_index` are
15+
// stablilized.
16+
#![allow(unexpected_cfgs)]
1317

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

27-
impl<T:PartialEq,constN:usize>PartialEqforSimd<T,N>{
28-
fneq(&self,other:&Self) -> bool{
29-
self.as_array() == other.as_array()
30-
}
31-
}
32-
3331
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforSimd<T,N>{
3432
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
3533
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
3634
}
3735
}
3836

39-
impl<T,constN:usize> core::ops::Index<usize>forSimd<T,N>{
40-
typeOutput = T;
41-
fnindex(&self,i:usize) -> &T{
42-
&self.as_array()[i]
43-
}
44-
}
45-
4637
impl<T,constN:usize>Simd<T,N>{
4738
pubconstfnfrom_array(a:[T;N]) -> Self{
4839
Simd(a)
4940
}
50-
pubfnas_array(&self) -> &[T;N]{
41+
pubconstfnas_array(&self) -> &[T;N]{
5142
let p:*constSelf = self;
5243
unsafe{&*p.cast::<[T;N]>()}
5344
}
54-
pubfninto_array(self) -> [T;N]
45+
pubconstfninto_array(self) -> [T;N]
5546
where
5647
T:Copy,
5748
{
5849
*self.as_array()
5950
}
51+
pubconstfnsplat(a:T) -> Self
52+
where
53+
T:Copy,
54+
{
55+
Self([a;N])
56+
}
6057
}
6158

6259
pubtypeu8x2 = Simd<u8,2>;
@@ -109,6 +106,14 @@ pub type i64x8 = Simd<i64, 8>;
109106
pubtypei128x2 = Simd<i128,2>;
110107
pubtypei128x4 = Simd<i128,4>;
111108

109+
pubtypeusizex2 = Simd<usize,2>;
110+
pubtypeusizex4 = Simd<usize,4>;
111+
pubtypeusizex8 = Simd<usize,8>;
112+
113+
pubtypeisizex2 = Simd<isize,2>;
114+
pubtypeisizex4 = Simd<isize,4>;
115+
pubtypeisizex8 = Simd<isize,8>;
116+
112117
pubtypef32x2 = Simd<f32,2>;
113118
pubtypef32x4 = Simd<f32,4>;
114119
pubtypef32x8 = Simd<f32,8>;
@@ -122,7 +127,7 @@ pub type f64x8 = Simd<f64, 8>;
122127
// which attempt to just construct it directly. That still works; it's just the
123128
// `.0` projection that doesn't.
124129
#[repr(simd, packed)]
125-
#[derive(Copy)]
130+
#[derive(Copy,Eq)]
126131
pubstructPackedSimd<T,constN:usize>(pub[T;N]);
127132

128133
impl<T:Copy,constN:usize>CloneforPackedSimd<T,N>{
@@ -131,12 +136,6 @@ impl<T: Copy, const N: usize> Clone for PackedSimd<T, N> {
131136
}
132137
}
133138

134-
impl<T:PartialEq,constN:usize>PartialEqforPackedSimd<T,N>{
135-
fneq(&self,other:&Self) -> bool{
136-
self.as_array() == other.as_array()
137-
}
138-
}
139-
140139
impl<T: core::fmt::Debug,constN:usize> core::fmt::DebugforPackedSimd<T,N>{
141140
fnfmt(&self,f:&mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error>{
142141
<[T;N]as core::fmt::Debug>::fmt(self.as_array(), f)
@@ -147,14 +146,81 @@ impl<T, const N: usize> PackedSimd<T, N> {
147146
pubconstfnfrom_array(a:[T;N]) -> Self{
148147
PackedSimd(a)
149148
}
150-
pubfnas_array(&self) -> &[T;N]{
149+
pubconstfnas_array(&self) -> &[T;N]{
151150
let p:*constSelf = self;
152151
unsafe{&*p.cast::<[T;N]>()}
153152
}
154-
pubfninto_array(self) -> [T;N]
153+
pubconstfninto_array(self) -> [T;N]
155154
where
156155
T:Copy,
157156
{
158157
*self.as_array()
159158
}
159+
pubconstfnsplat(a:T) -> Self
160+
where
161+
T:Copy,
162+
{
163+
Self([a;N])
164+
}
165+
}
166+
167+
// As `const_trait_impl` is a language feature with specialized syntax, we have to use them in a way
168+
// such that it doesn't get parsed as Rust code unless `cfg(minisimd_const)` is on. The easiest way
169+
// for that is a macro
170+
171+
macro_rules! impl_traits {
172+
($($const_:ident)?) => {
173+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforSimd<T,N> {
174+
fn eq(&self, other:&Self) -> bool{
175+
self.as_array() == other.as_array()
176+
}
177+
}
178+
179+
impl<T,constN:usize> $($const_)? core::ops::Index<usize> forSimd<T,N> {
180+
typeOutput = T;
181+
fn index(&self, i:usize) -> &T{
182+
&self.as_array()[i]
183+
}
184+
}
185+
186+
impl<T: $([$const_])? PartialEq,constN:usize> $($const_)? PartialEqforPackedSimd<T,N>
187+
{
188+
fn eq(&self, other:&Self) -> bool{
189+
self.as_array() == other.as_array()
190+
}
191+
}
192+
};
160193
}
194+
195+
#[cfg(minisimd_const)]
196+
impl_traits!(const);
197+
198+
#[cfg(not(minisimd_const))]
199+
impl_traits!();
200+
201+
/// Version of `assert_eq` that ignores fancy runtime printing in const context.
202+
/// FIXME: Remove once <https://github.com/rust-lang/rust/issues/119826> is fixed.
203+
#[cfg(minisimd_const)]
204+
#[macro_export]
205+
macro_rules! assert_eq {
206+
($left:expr, $right:expr $(,)?) => {
207+
assert_eq!(
208+
$left,
209+
$right,
210+
concat!("`", stringify!($left),"` == `", stringify!($right),"`")
211+
);
212+
};
213+
($left:expr, $right:expr$(, $($arg:tt)+)?) => {
214+
{
215+
let left = $left;
216+
let right = $right;
217+
// type inference works better with the concrete type on the
218+
// left, but humans work better with the expected on the
219+
// right
220+
assert!(right == left, $($($arg)*),*);
221+
}
222+
};
223+
}
224+
225+
#[cfg(minisimd_const)]
226+
use assert_eq;
Lines changed: 42 additions & 25 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"]
@@ -20,7 +21,10 @@ use std::intrinsics::simd::*;
2021
macro_rules! assert_approx_eq_f32 {
2122
($a:expr, $b:expr) => {{
2223
let(a, b) = (&$a,&$b);
23-
assert!((*a - *b).abs() < 1.0e-6,"{} is not approximately equal to {}",*a,*b);
24+
assert!(
25+
(*a - *b).abs() < 1.0e-6,
26+
concat!(stringify!($a)," is not approximately equal to ", stringify!($b))
27+
);
2428
}};
2529
}
2630
macro_rules! assert_approx_eq {
@@ -34,7 +38,7 @@ macro_rules! assert_approx_eq {
3438
}};
3539
}
3640

37-
fnmain(){
41+
constfnsimple_math(){
3842
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
3943
let y = f32x4::from_array([-1.0, -1.0, -1.0, -1.0]);
4044
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
@@ -43,21 +47,44 @@ fn main() {
4347

4448
unsafe{
4549
let r = simd_fabs(y);
46-
assert_approx_eq!(x, r);
50+
assert_eq!(x, r);
4751

48-
let r = simd_fcos(z);
52+
// rounding functions
53+
let r = simd_floor(h);
54+
assert_eq!(z, r);
55+
56+
let r = simd_ceil(h);
57+
assert_eq!(x, r);
58+
59+
let r = simd_round(h);
60+
assert_eq!(x, r);
61+
62+
let r = simd_round_ties_even(h);
63+
assert_eq!(z, r);
64+
65+
let r = simd_trunc(h);
66+
assert_eq!(z, r);
67+
68+
let r = simd_fma(x, h, h);
4969
assert_approx_eq!(x, r);
5070

51-
let r = simd_fexp(z);
71+
let r = simd_relaxed_fma(x, h, h);
5272
assert_approx_eq!(x, r);
73+
}
74+
}
5375

54-
let r = simd_fexp2(z);
76+
fnspecial_math(){
77+
let x = f32x4::from_array([1.0,1.0,1.0,1.0]);
78+
let z = f32x4::from_array([0.0,0.0,0.0,0.0]);
79+
80+
unsafe{
81+
let r = simd_fcos(z);
5582
assert_approx_eq!(x, r);
5683

57-
let r = simd_fma(x, h, h);
84+
let r = simd_fexp(z);
5885
assert_approx_eq!(x, r);
5986

60-
let r = simd_relaxed_fma(x, h, h);
87+
let r = simd_fexp2(z);
6188
assert_approx_eq!(x, r);
6289

6390
let r = simd_fsqrt(x);
@@ -74,21 +101,11 @@ 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+
fnmain(){
108+
const{simple_math()};
109+
simple_math();
110+
special_math();
111+
}

‎tests/ui/simd/intrinsic/float-minmax-pass.rs‎

Lines changed: 8 additions & 2 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-
fnmain(){
16+
constfnminmax(){
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

@@ -47,3 +48,8 @@ fn main() {
4748
assert_eq!(maxn, y);
4849
}
4950
}
51+
52+
fnmain(){
53+
const{minmax()};
54+
minmax();
55+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-backends: gcc
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -20,7 +21,7 @@ macro_rules! all_eq {
2021

2122
use std::intrinsics::simd::*;
2223

23-
fnmain(){
24+
constfnarithmetic(){
2425
let x1 = i32x4::from_array([1,2,3,4]);
2526
let y1 = U32::<4>::from_array([1,2,3,4]);
2627
let z1 = f32x4::from_array([1.0,2.0,3.0,4.0]);
@@ -224,3 +225,8 @@ fn main() {
224225
all_eq!(simd_cttz(y1),U32::<4>::from_array([0,1,0,2]));
225226
}
226227
}
228+
229+
fnmain(){
230+
const{arithmetic()};
231+
arithmetic();
232+
}

‎tests/ui/simd/intrinsic/generic-arithmetic-saturating-pass.rs‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
//@ run-pass
22
//@ ignore-emscripten
3+
//@ compile-flags: --cfg minisimd_const
34

45
#![allow(non_camel_case_types)]
5-
#![feature(repr_simd, core_intrinsics)]
6+
#![feature(repr_simd, core_intrinsics, const_trait_impl, const_cmp, const_index)]
67

78
#[path = "../../../auxiliary/minisimd.rs"]
89
mod minisimd;
@@ -12,7 +13,7 @@ use std::intrinsics::simd::{simd_saturating_add, simd_saturating_sub};
1213

1314
typeI32<constN:usize> = Simd<i32,N>;
1415

15-
fnmain(){
16+
constfnsaturating(){
1617
// unsigned
1718
{
1819
constM:u32 = u32::MAX;
@@ -84,3 +85,8 @@ fn main() {
8485
}
8586
}
8687
}
88+
89+
fnmain(){
90+
const{saturating()};
91+
saturating();
92+
}

0 commit comments

Comments
 (0)