Skip to content

Commit

Permalink
Add const-eval support for SIMD types, insert, and extract
Browse files Browse the repository at this point in the history
  • Loading branch information
gnzlbg committed Sep 24, 2019
1 parent ef906d0 commit 03ac54a
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 2 deletions.
20 changes: 19 additions & 1 deletion src/librustc_mir/interpret/intrinsics.rs
Expand Up @@ -239,7 +239,25 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
"transmute" => {
self.copy_op_transmute(args[0], dest)?;
}

"simd_insert" => {
let mut vector = self.read_vector(args[0])?;
let index = self.read_scalar(args[1])?.to_u32()? as usize;
let scalar = self.read_immediate(args[2])?;
if vector[index].layout.size == scalar.layout.size {
vector[index] = scalar;
} else {
throw_ub_format!(
"Inserting `{:?}` with size `{}` to a vector element place of size `{}`",
scalar, scalar.layout.size.bytes(), vector[index].layout.size.bytes()
);
}
self.write_vector(vector, dest)?;
}
"simd_extract" => {
let index = self.read_scalar(args[1])?.to_u32()? as _;
let scalar = self.read_immediate(self.operand_field(args[0], index)?)?;
self.write_immediate(*scalar, dest)?;
}
_ => return Ok(false),
}

Expand Down
15 changes: 15 additions & 0 deletions src/librustc_mir/interpret/operand.rs
Expand Up @@ -335,6 +335,21 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}

/// Read vector from operand `op`
pub fn read_vector(&self, op: OpTy<'tcx, M::PointerTag>)
-> InterpResult<'tcx, Vec<ImmTy<'tcx, M::PointerTag>>> {
if let layout::Abi::Vector { count, .. } = op.layout.abi {
assert_ne!(count, 0);
let mut scalars = Vec::new();
for index in 0..count {
scalars.push(self.read_immediate(self.operand_field(op, index as _)?)?);
}
Ok(scalars)
} else {
bug!("type is not a vector: {:?}, abi: {:?}", op.layout.ty, op.layout.abi);
}
}

/// Read a scalar from a place
pub fn read_scalar(
&self,
Expand Down
34 changes: 34 additions & 0 deletions src/librustc_mir/interpret/place.rs
Expand Up @@ -696,6 +696,40 @@ where
Ok(())
}

/// Writes the `scalar` to the `index`-th element of the `vector`.
pub fn write_scalar_to_vector(
&mut self,
scalar: ImmTy<'tcx, M::PointerTag>,
vector: PlaceTy<'tcx, M::PointerTag>,
index: usize,
) -> InterpResult<'tcx> {
let index = index as u64;
let place = self.place_field(vector, index)?;
self.write_immediate(*scalar, place)?;
Ok(())
}

/// Writes the `scalars` to the `vector`.
pub fn write_vector(
&mut self,
scalars: Vec<ImmTy<'tcx, M::PointerTag>>,
vector: PlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx> {
assert_ne!(scalars.len(), 0);
match vector.layout.ty.sty {
ty::Adt(def, ..) if def.repr.simd() => {
let tcx = &*self.tcx;
let count = vector.layout.ty.simd_size(*tcx);
assert_eq!(count, scalars.len());
for index in 0..scalars.len() {
self.write_scalar_to_vector(scalars[index], vector, index)?;
}
}
_ => bug!("not a vector"),
}
Ok(())
}

/// Write an `Immediate` to memory.
#[inline(always)]
pub fn write_immediate_to_mplace(
Expand Down
4 changes: 3 additions & 1 deletion src/librustc_mir/interpret/terminator.rs
Expand Up @@ -249,7 +249,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {

match instance.def {
ty::InstanceDef::Intrinsic(..) => {
if caller_abi != Abi::RustIntrinsic {
if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = caller_abi {
// ok
} else {
throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic))
}
// The intrinsic itself cannot diverge, so if we got here without a return
Expand Down
24 changes: 24 additions & 0 deletions src/test/ui/consts/const-eval/const_eval-simd.rs
@@ -0,0 +1,24 @@
// run-pass
// compile-flags: -Zunleash-the-miri-inside-of-you
#![feature(repr_simd)]
#![feature(platform_intrinsics)]
#![allow(non_camel_case_types)]

#[repr(simd)] struct i8x1(i8);

extern "platform-intrinsic" {
fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
fn simd_extract<T, U>(x: T, idx: u32) -> U;
}

const fn foo(x: i8x1) -> i8 {
unsafe { simd_insert(x, 0_u32, 42_i8) }.0
}

fn main() {
const V: i8x1 = i8x1(13);
const X: i8 = foo(V);
const Y: i8 = unsafe { simd_extract(V, 0) };
assert_eq!(X, 42);
assert_eq!(Y, 13);
}
48 changes: 48 additions & 0 deletions src/test/ui/consts/const-eval/const_eval-simd.stderr
@@ -0,0 +1,48 @@
warning: skipping const checks
--> $DIR/const_eval-simd.rs:22:5
|
LL | assert_eq!(X, 42);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

warning: skipping const checks
--> $DIR/const_eval-simd.rs:22:5
|
LL | assert_eq!(X, 42);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

warning: skipping const checks
--> $DIR/const_eval-simd.rs:22:5
|
LL | assert_eq!(X, 42);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

warning: skipping const checks
--> $DIR/const_eval-simd.rs:23:5
|
LL | assert_eq!(Y, 13);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

warning: skipping const checks
--> $DIR/const_eval-simd.rs:23:5
|
LL | assert_eq!(Y, 13);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

warning: skipping const checks
--> $DIR/const_eval-simd.rs:23:5
|
LL | assert_eq!(Y, 13);
| ^^^^^^^^^^^^^^^^^^
|
= note: this warning originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)

0 comments on commit 03ac54a

Please sign in to comment.