Skip to content

Commit 03ac54a

Browse files
committed
Add const-eval support for SIMD types, insert, and extract
1 parent ef906d0 commit 03ac54a

File tree

6 files changed

+143
-2
lines changed

6 files changed

+143
-2
lines changed

src/librustc_mir/interpret/intrinsics.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
239239
"transmute" => {
240240
self.copy_op_transmute(args[0], dest)?;
241241
}
242-
242+
"simd_insert" => {
243+
let mut vector = self.read_vector(args[0])?;
244+
let index = self.read_scalar(args[1])?.to_u32()? as usize;
245+
let scalar = self.read_immediate(args[2])?;
246+
if vector[index].layout.size == scalar.layout.size {
247+
vector[index] = scalar;
248+
} else {
249+
throw_ub_format!(
250+
"Inserting `{:?}` with size `{}` to a vector element place of size `{}`",
251+
scalar, scalar.layout.size.bytes(), vector[index].layout.size.bytes()
252+
);
253+
}
254+
self.write_vector(vector, dest)?;
255+
}
256+
"simd_extract" => {
257+
let index = self.read_scalar(args[1])?.to_u32()? as _;
258+
let scalar = self.read_immediate(self.operand_field(args[0], index)?)?;
259+
self.write_immediate(*scalar, dest)?;
260+
}
243261
_ => return Ok(false),
244262
}
245263

src/librustc_mir/interpret/operand.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
335335
}
336336
}
337337

338+
/// Read vector from operand `op`
339+
pub fn read_vector(&self, op: OpTy<'tcx, M::PointerTag>)
340+
-> InterpResult<'tcx, Vec<ImmTy<'tcx, M::PointerTag>>> {
341+
if let layout::Abi::Vector { count, .. } = op.layout.abi {
342+
assert_ne!(count, 0);
343+
let mut scalars = Vec::new();
344+
for index in 0..count {
345+
scalars.push(self.read_immediate(self.operand_field(op, index as _)?)?);
346+
}
347+
Ok(scalars)
348+
} else {
349+
bug!("type is not a vector: {:?}, abi: {:?}", op.layout.ty, op.layout.abi);
350+
}
351+
}
352+
338353
/// Read a scalar from a place
339354
pub fn read_scalar(
340355
&self,

src/librustc_mir/interpret/place.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,40 @@ where
696696
Ok(())
697697
}
698698

699+
/// Writes the `scalar` to the `index`-th element of the `vector`.
700+
pub fn write_scalar_to_vector(
701+
&mut self,
702+
scalar: ImmTy<'tcx, M::PointerTag>,
703+
vector: PlaceTy<'tcx, M::PointerTag>,
704+
index: usize,
705+
) -> InterpResult<'tcx> {
706+
let index = index as u64;
707+
let place = self.place_field(vector, index)?;
708+
self.write_immediate(*scalar, place)?;
709+
Ok(())
710+
}
711+
712+
/// Writes the `scalars` to the `vector`.
713+
pub fn write_vector(
714+
&mut self,
715+
scalars: Vec<ImmTy<'tcx, M::PointerTag>>,
716+
vector: PlaceTy<'tcx, M::PointerTag>,
717+
) -> InterpResult<'tcx> {
718+
assert_ne!(scalars.len(), 0);
719+
match vector.layout.ty.sty {
720+
ty::Adt(def, ..) if def.repr.simd() => {
721+
let tcx = &*self.tcx;
722+
let count = vector.layout.ty.simd_size(*tcx);
723+
assert_eq!(count, scalars.len());
724+
for index in 0..scalars.len() {
725+
self.write_scalar_to_vector(scalars[index], vector, index)?;
726+
}
727+
}
728+
_ => bug!("not a vector"),
729+
}
730+
Ok(())
731+
}
732+
699733
/// Write an `Immediate` to memory.
700734
#[inline(always)]
701735
pub fn write_immediate_to_mplace(

src/librustc_mir/interpret/terminator.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
249249

250250
match instance.def {
251251
ty::InstanceDef::Intrinsic(..) => {
252-
if caller_abi != Abi::RustIntrinsic {
252+
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = caller_abi {
253+
// ok
254+
} else {
253255
throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
254256
}
255257
// The intrinsic itself cannot diverge, so if we got here without a return
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// run-pass
2+
// compile-flags: -Zunleash-the-miri-inside-of-you
3+
#![feature(repr_simd)]
4+
#![feature(platform_intrinsics)]
5+
#![allow(non_camel_case_types)]
6+
7+
#[repr(simd)] struct i8x1(i8);
8+
9+
extern "platform-intrinsic" {
10+
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
11+
fn simd_extract<T, U>(x: T, idx: u32) -> U;
12+
}
13+
14+
const fn foo(x: i8x1) -> i8 {
15+
unsafe { simd_insert(x, 0_u32, 42_i8) }.0
16+
}
17+
18+
fn main() {
19+
const V: i8x1 = i8x1(13);
20+
const X: i8 = foo(V);
21+
const Y: i8 = unsafe { simd_extract(V, 0) };
22+
assert_eq!(X, 42);
23+
assert_eq!(Y, 13);
24+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
warning: skipping const checks
2+
--> $DIR/const_eval-simd.rs:22:5
3+
|
4+
LL | assert_eq!(X, 42);
5+
| ^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
8+
9+
warning: skipping const checks
10+
--> $DIR/const_eval-simd.rs:22:5
11+
|
12+
LL | assert_eq!(X, 42);
13+
| ^^^^^^^^^^^^^^^^^^
14+
|
15+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
16+
17+
warning: skipping const checks
18+
--> $DIR/const_eval-simd.rs:22:5
19+
|
20+
LL | assert_eq!(X, 42);
21+
| ^^^^^^^^^^^^^^^^^^
22+
|
23+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
24+
25+
warning: skipping const checks
26+
--> $DIR/const_eval-simd.rs:23:5
27+
|
28+
LL | assert_eq!(Y, 13);
29+
| ^^^^^^^^^^^^^^^^^^
30+
|
31+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
32+
33+
warning: skipping const checks
34+
--> $DIR/const_eval-simd.rs:23:5
35+
|
36+
LL | assert_eq!(Y, 13);
37+
| ^^^^^^^^^^^^^^^^^^
38+
|
39+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
40+
41+
warning: skipping const checks
42+
--> $DIR/const_eval-simd.rs:23:5
43+
|
44+
LL | assert_eq!(Y, 13);
45+
| ^^^^^^^^^^^^^^^^^^
46+
|
47+
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)
48+

0 commit comments

Comments
 (0)