diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index ec09e69ec8537..5fc23b4a69ec5 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -239,7 +239,52 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { "transmute" => { self.copy_op_transmute(args[0], dest)?; } + "simd_insert" => { + let index = self.read_scalar(args[1])?.to_u32()? as u64; + let scalar = args[2]; + let input = args[0]; + let (len, e_ty) = self.read_vector_ty(input); + assert!( + index < len, + "Index `{}` must be in bounds of vector type `{}`: `[0, {})`", + index, e_ty, len + ); + assert_eq!( + input.layout, dest.layout, + "Return type `{}` must match vector type `{}`", + dest.layout.ty, input.layout.ty + ); + assert_eq!( + scalar.layout.ty, e_ty, + "Scalar type `{}` must match vector element type `{}`", + scalar.layout.ty, e_ty + ); + for i in 0..len { + let place = self.place_field(dest, i)?; + let value = if i == index { + scalar + } else { + self.operand_field(input, i)? + }; + self.copy_op(value, place)?; + } + } + "simd_extract" => { + let index = self.read_scalar(args[1])?.to_u32()? as _; + let (len, e_ty) = self.read_vector_ty(args[0]); + assert!( + index < len, + "index `{}` is out-of-bounds of vector type `{}` with length `{}`", + index, e_ty, len + ); + assert_eq!( + e_ty, dest.layout.ty, + "Return type `{}` must match vector element type `{}`", + dest.layout.ty, e_ty + ); + self.copy_op(self.operand_field(args[0], index)?, dest)?; + } _ => return Ok(false), } diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index dd214c4a031f7..afaf9d7ed9d67 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -335,6 +335,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + /// Read vector length and element type + pub fn read_vector_ty( + &self, op: OpTy<'tcx, M::PointerTag> + ) -> (u64, &rustc::ty::TyS<'tcx>) { + if let layout::Abi::Vector { .. } = op.layout.abi { + (op.layout.ty.simd_size(*self.tcx) as _, op.layout.ty.simd_type(*self.tcx)) + } else { + bug!("Type `{}` is not a SIMD vector type", op.layout.ty) + } + } + /// Read a scalar from a place pub fn read_scalar( &self, diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs index 8310ef02f9669..8666c937ce4c2 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/src/librustc_mir/interpret/terminator.rs @@ -249,9 +249,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(..) => { - if caller_abi != Abi::RustIntrinsic { - throw_unsup!(FunctionAbiMismatch(caller_abi, Abi::RustIntrinsic)) - } // The intrinsic itself cannot diverge, so if we got here without a return // place... (can happen e.g., for transmute returning `!`) let dest = match dest { diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 795721f3b3f28..8a6dcd1d2b476 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -557,6 +557,8 @@ impl Qualif for IsNotPromotable { | "saturating_add" | "saturating_sub" | "transmute" + | "simd_insert" + | "simd_extract" => return true, _ => {} diff --git a/src/test/ui/consts/const-eval/simd/insert_extract.rs b/src/test/ui/consts/const-eval/simd/insert_extract.rs new file mode 100644 index 0000000000000..d3462d802ea4e --- /dev/null +++ b/src/test/ui/consts/const-eval/simd/insert_extract.rs @@ -0,0 +1,53 @@ +// run-pass +#![feature(const_fn)] +#![feature(repr_simd)] +#![feature(platform_intrinsics)] +#![allow(non_camel_case_types)] + +#[repr(simd)] struct i8x1(i8); +#[repr(simd)] struct u16x2(u16, u16); +#[repr(simd)] struct f32x3(f32, f32, f32); + +extern "platform-intrinsic" { + fn simd_insert(x: T, idx: u32, val: U) -> T; + fn simd_extract(x: T, idx: u32) -> U; +} + +fn main() { + { + const U: i8x1 = i8x1(13); + const V: i8x1 = unsafe { simd_insert(U, 0_u32, 42_i8) }; + const X0: i8 = V.0; + const Y0: i8 = unsafe { simd_extract(V, 0) }; + assert_eq!(X0, 42); + assert_eq!(Y0, 42); + } + { + const U: u16x2 = u16x2(13, 14); + const V: u16x2 = unsafe { simd_insert(U, 1_u32, 42_u16) }; + const X0: u16 = V.0; + const X1: u16 = V.1; + const Y0: u16 = unsafe { simd_extract(V, 0) }; + const Y1: u16 = unsafe { simd_extract(V, 1) }; + assert_eq!(X0, 13); + assert_eq!(X1, 42); + assert_eq!(Y0, 13); + assert_eq!(Y1, 42); + } + { + const U: f32x3 = f32x3(13., 14., 15.); + const V: f32x3 = unsafe { simd_insert(U, 1_u32, 42_f32) }; + const X0: f32 = V.0; + const X1: f32 = V.1; + const X2: f32 = V.2; + const Y0: f32 = unsafe { simd_extract(V, 0) }; + const Y1: f32 = unsafe { simd_extract(V, 1) }; + const Y2: f32 = unsafe { simd_extract(V, 2) }; + assert_eq!(X0, 13.); + assert_eq!(X1, 42.); + assert_eq!(X2, 15.); + assert_eq!(Y0, 13.); + assert_eq!(Y1, 42.); + assert_eq!(Y2, 15.); + } +}