diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ec09e69ec853..0ede06819059 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -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), } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index dd214c4a031f..184e2ee9516f 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -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>> { + 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, diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index c3660fb7a2e2..9154e2666c59 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -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>, + 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( diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 8310ef02f966..a324c5851240 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -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 diff --git a/src/test/ui/consts/const-eval/const_eval-simd.rs b/src/test/ui/consts/const-eval/const_eval-simd.rs new file mode 100644 index 000000000000..a0f088cc636f --- /dev/null +++ b/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(x: T, idx: u32, val: U) -> T; + fn simd_extract(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); +} diff --git a/src/test/ui/consts/const-eval/const_eval-simd.stderr b/src/test/ui/consts/const-eval/const_eval-simd.stderr new file mode 100644 index 000000000000..7fc068718b0b --- /dev/null +++ b/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) +