diff --git a/src/librustc_mir/interpret/intrinsics.rs b/src/librustc_mir/interpret/intrinsics.rs index fc1ec61c9629e..586611397e344 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/src/librustc_mir/interpret/intrinsics.rs @@ -240,24 +240,55 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 index = self.read_scalar(args[1])?.to_u32()? as u64; 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.layout.ty, - scalar.layout.size.bytes(), vector[index].layout.size.bytes() - ); + 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!( + args[0].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, index)?; + if i == index { + self.write_immediate(*scalar, place)?; + } else { + self.write_immediate( + *self.read_immediate(self.operand_field(input, index)?)?, + place + )?; + }; } - 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)?; + let (len, e_ty) = self.read_vector_ty(args[0]); + assert!( + index < len, + "index `{}` must be in bounds of vector type `{}`: `[0, {})`", + index, e_ty, len + ); + assert_eq!( + e_ty, dest.layout.ty, + "Return type `{}` must match vector element type `{}`", + dest.layout.ty, e_ty + ); + self.write_immediate( + *self.read_immediate(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 184e2ee9516fc..c5771e4f34378 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -335,18 +335,15 @@ 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) + /// 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 vector: {:?}, abi: {:?}", op.layout.ty, op.layout.abi); + bug!("Type `{}` is not a SIMD vector type", op.layout.ty) } } diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index 9154e2666c598..c3660fb7a2e28 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -696,40 +696,6 @@ 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/test/ui/consts/const-eval/simd/insert_extract-fail.rs b/src/test/ui/consts/const-eval/simd/insert_extract-fail.rs index bbfae997e7241..1d1df8d25a406 100644 --- a/src/test/ui/consts/const-eval/simd/insert_extract-fail.rs +++ b/src/test/ui/consts/const-eval/simd/insert_extract-fail.rs @@ -7,6 +7,7 @@ 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 { @@ -14,7 +15,13 @@ const fn foo(x: i8x1) -> i8 { unsafe { simd_insert(x, 0_u32, 42_i16) }.0 //~ ERROR } +const fn bar(x: i8x1) -> i16 { + // the i8 is not a i16: + unsafe { simd_extract(x, 0_u32) } //~ ERROR +} + fn main() { const V: i8x1 = i8x1(13); const X: i8 = foo(V); + const Y: i16 = bar(V); } diff --git a/src/test/ui/consts/const-eval/simd/read_fail.rs b/src/test/ui/consts/const-eval/simd/read_fail.rs new file mode 100644 index 0000000000000..c5109c16e4c6d --- /dev/null +++ b/src/test/ui/consts/const-eval/simd/read_fail.rs @@ -0,0 +1,17 @@ +#![feature(const_fn)] +#![feature(platform_intrinsics)] +#![allow(non_camel_case_types)] + +extern "platform-intrinsic" { + fn simd_extract(x: T, idx: u32) -> U; +} + +const fn foo(x: i8) -> i8 { + // i8 is not a vector type: + unsafe { simd_extract(x, 0_u32) } //~ ERROR +} + +fn main() { + const V: i8 = 13; + const X: i8 = foo(V); +}