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),
}
}
}
- /// 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)
+ /// 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)
}
}
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(
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_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);
}
--- /dev/null
+#![feature(const_fn)]
+#![feature(platform_intrinsics)]
+#![allow(non_camel_case_types)]
+
+extern "platform-intrinsic" {
+ fn simd_extract<T, U>(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);
+}