Skip to content

Commit 8c569d6

Browse files
committed
Implement simd_shuffle in const_eval
1 parent 52618eb commit 8c569d6

File tree

3 files changed

+96
-1
lines changed

3 files changed

+96
-1
lines changed

compiler/rustc_const_eval/src/interpret/intrinsics.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,39 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
485485
}
486486
self.copy_op(&self.project_index(&input, index)?, dest)?;
487487
}
488+
sym::simd_shuffle => {
489+
let (x, input_len) = self.project_to_simd(&args[0])?;
490+
let (y, _) = self.project_to_simd(&args[1])?;
491+
let (shuffle, shuffle_len) = self.project_to_simd(&args[2])?;
492+
let (dest, dest_len) = self.project_to_simd(dest)?;
493+
assert_eq!(
494+
shuffle_len, dest_len,
495+
"Return vector length must match shuffle vector length"
496+
);
497+
assert_eq!(
498+
shuffle.layout.ty.sequence_element_type(*self.tcx).kind(),
499+
&ty::Uint(ty::UintTy::U32),
500+
"Shuffle vector must be a vector of `u32`s"
501+
);
502+
503+
for i in 0..dest_len {
504+
let idx = self.project_index(&shuffle, i)?;
505+
let idx = u64::from(self.read_scalar(&idx)?.to_u32()?);
506+
if idx >= 2 * input_len {
507+
throw_ub_format!(
508+
"`simd_shuffle` index {idx} is out-of-bounds of vector with length {input_len}"
509+
);
510+
}
511+
512+
let value = if idx < input_len {
513+
self.project_index(&x, idx)?
514+
} else {
515+
self.project_index(&y, idx - input_len)?
516+
};
517+
let place = self.project_index(&dest, i)?;
518+
self.copy_op(&value, &place)?;
519+
}
520+
}
488521
sym::black_box => {
489522
// These just return their argument
490523
self.copy_op(&args[0], dest)?;

library/core/src/intrinsics/simd.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,7 +330,7 @@ pub unsafe fn simd_ge<T, U>(x: T, y: T) -> U;
330330
/// of `xy`.
331331
#[rustc_intrinsic]
332332
#[rustc_nounwind]
333-
pub unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
333+
pub const unsafe fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
334334

335335
/// Reads a vector of pointers.
336336
///
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//@ run-pass
2+
3+
// these tests are copied from `tests/ui/simd/intrinsic/generic-elements-pass.rs`
4+
#![feature(repr_simd, intrinsics, core_intrinsics)]
5+
6+
#[path = "../../../../auxiliary/minisimd.rs"]
7+
mod minisimd;
8+
use std::intrinsics::simd::simd_shuffle;
9+
10+
use minisimd::*;
11+
12+
#[repr(simd)]
13+
struct SimdShuffleIdx<const LEN: usize>([u32; LEN]);
14+
15+
macro_rules! all_eq {
16+
($a: expr, $b: expr) => {{
17+
let a = $a;
18+
let b = $b;
19+
// type inference works better with the concrete type on the
20+
// left, but humans work better with the expected on the
21+
// right.
22+
assert!(b == a, "{:?} != {:?}", a, b);
23+
}};
24+
}
25+
26+
macro_rules! simd_shuffle {
27+
($a: expr, $b: expr, $shuffle: expr) => {
28+
const { simd_shuffle($a, $b, const { SimdShuffleIdx($shuffle) } ) }
29+
};
30+
}
31+
32+
fn main() {
33+
const X2: i32x2 = i32x2::from_array([20, 21]);
34+
const X4: i32x4 = i32x4::from_array([40, 41, 42, 43]);
35+
const X8: i32x8 = i32x8::from_array([80, 81, 82, 83, 84, 85, 86, 87]);
36+
37+
const Y2: i32x2 = i32x2::from_array([120, 121]);
38+
const Y4: i32x4 = i32x4::from_array([140, 141, 142, 143]);
39+
const Y8: i32x8 = i32x8::from_array([180, 181, 182, 183, 184, 185, 186, 187]);
40+
unsafe {
41+
all_eq!(simd_shuffle!(X2, Y2, [3, 0]), i32x2::from_array([121, 20]));
42+
all_eq!(simd_shuffle!(X2, Y2, [3, 0, 1, 2]), i32x4::from_array([121, 20, 21, 120]));
43+
all_eq!(
44+
simd_shuffle!(X2, Y2, [3, 0, 1, 2, 1, 2, 3, 0]),
45+
i32x8::from_array([121, 20, 21, 120, 21, 120, 121, 20])
46+
);
47+
48+
all_eq!(simd_shuffle!(X4, Y4, [7, 2]), i32x2::from_array([143, 42]));
49+
all_eq!(simd_shuffle!(X4, Y4, [7, 2, 5, 0]), i32x4::from_array([143, 42, 141, 40]));
50+
all_eq!(
51+
simd_shuffle!(X4, Y4, [7, 2, 5, 0, 3, 6, 4, 1]),
52+
i32x8::from_array([143, 42, 141, 40, 43, 142, 140, 41])
53+
);
54+
55+
all_eq!(simd_shuffle!(X8, Y8, [11, 5]), i32x2::from_array([183, 85]));
56+
all_eq!(simd_shuffle!(X8, Y8, [11, 5, 15, 0]), i32x4::from_array([183, 85, 187, 80]));
57+
all_eq!(
58+
simd_shuffle!(X8, Y8, [11, 5, 15, 0, 3, 8, 12, 1]),
59+
i32x8::from_array([183, 85, 187, 80, 83, 180, 184, 81])
60+
);
61+
}
62+
}

0 commit comments

Comments
 (0)