interpret: simplify SIMD type handling
This commit is contained in:
parent
a5efa01895
commit
e2bc16c101
15 changed files with 190 additions and 199 deletions
|
@ -384,8 +384,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
sym::simd_insert => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let elem = &args[2];
|
||||
let (input, input_len) = self.operand_to_simd(&args[0])?;
|
||||
let (dest, dest_len) = self.mplace_to_simd(dest)?;
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
let (dest, dest_len) = self.project_to_simd(dest)?;
|
||||
assert_eq!(input_len, dest_len, "Return vector length must match input length");
|
||||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
|
@ -406,7 +406,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
}
|
||||
sym::simd_extract => {
|
||||
let index = u64::from(self.read_scalar(&args[1])?.to_u32()?);
|
||||
let (input, input_len) = self.operand_to_simd(&args[0])?;
|
||||
let (input, input_len) = self.project_to_simd(&args[0])?;
|
||||
// Bounds are not checked by typeck so we have to do it ourselves.
|
||||
if index >= input_len {
|
||||
throw_ub_format!(
|
||||
|
|
|
@ -681,30 +681,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
|
|||
Ok(str)
|
||||
}
|
||||
|
||||
/// Converts a repr(simd) operand into an operand where `place_index` accesses the SIMD elements.
|
||||
/// Also returns the number of elements.
|
||||
///
|
||||
/// Can (but does not always) trigger UB if `op` is uninitialized.
|
||||
pub fn operand_to_simd(
|
||||
&self,
|
||||
op: &OpTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
|
||||
// Basically we just transmute this place into an array following simd_size_and_type.
|
||||
// This only works in memory, but repr(simd) types should never be immediates anyway.
|
||||
assert!(op.layout.ty.is_simd());
|
||||
match op.as_mplace_or_imm() {
|
||||
Left(mplace) => self.mplace_to_simd(&mplace),
|
||||
Right(imm) => match *imm {
|
||||
Immediate::Uninit => {
|
||||
throw_ub!(InvalidUninitBytes(None))
|
||||
}
|
||||
Immediate::Scalar(..) | Immediate::ScalarPair(..) => {
|
||||
bug!("arrays/slices can never have Scalar/ScalarPair layout")
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Read from a local of the current frame.
|
||||
/// Will not access memory, instead an indirect `Operand` is returned.
|
||||
///
|
||||
|
|
|
@ -377,13 +377,15 @@ where
|
|||
Prov: Provenance,
|
||||
M: Machine<'tcx, Provenance = Prov>,
|
||||
{
|
||||
pub fn ptr_with_meta_to_mplace(
|
||||
fn ptr_with_meta_to_mplace(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
meta: MemPlaceMeta<M::Provenance>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
unaligned: bool,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
let misaligned = self.is_ptr_misaligned(ptr, layout.align.abi);
|
||||
let misaligned =
|
||||
if unaligned { None } else { self.is_ptr_misaligned(ptr, layout.align.abi) };
|
||||
MPlaceTy { mplace: MemPlace { ptr, meta, misaligned }, layout }
|
||||
}
|
||||
|
||||
|
@ -393,7 +395,16 @@ where
|
|||
layout: TyAndLayout<'tcx>,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
assert!(layout.is_sized());
|
||||
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout)
|
||||
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ false)
|
||||
}
|
||||
|
||||
pub fn ptr_to_mplace_unaligned(
|
||||
&self,
|
||||
ptr: Pointer<Option<M::Provenance>>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
) -> MPlaceTy<'tcx, M::Provenance> {
|
||||
assert!(layout.is_sized());
|
||||
self.ptr_with_meta_to_mplace(ptr, MemPlaceMeta::None, layout, /*unaligned*/ true)
|
||||
}
|
||||
|
||||
/// Take a value, which represents a (thin or wide) reference, and make it a place.
|
||||
|
@ -414,7 +425,7 @@ where
|
|||
// `ref_to_mplace` is called on raw pointers even if they don't actually get dereferenced;
|
||||
// we hence can't call `size_and_align_of` since that asserts more validity than we want.
|
||||
let ptr = ptr.to_pointer(self)?;
|
||||
Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout))
|
||||
Ok(self.ptr_with_meta_to_mplace(ptr, meta, layout, /*unaligned*/ false))
|
||||
}
|
||||
|
||||
/// Turn a mplace into a (thin or wide) mutable raw pointer, pointing to the same space.
|
||||
|
@ -484,23 +495,6 @@ where
|
|||
Ok(a)
|
||||
}
|
||||
|
||||
/// Converts a repr(simd) place into a place where `place_index` accesses the SIMD elements.
|
||||
/// Also returns the number of elements.
|
||||
pub fn mplace_to_simd(
|
||||
&self,
|
||||
mplace: &MPlaceTy<'tcx, M::Provenance>,
|
||||
) -> InterpResult<'tcx, (MPlaceTy<'tcx, M::Provenance>, u64)> {
|
||||
// Basically we want to transmute this place into an array following simd_size_and_type.
|
||||
let (len, e_ty) = mplace.layout.ty.simd_size_and_type(*self.tcx);
|
||||
// Some SIMD types have padding, so `len` many `e_ty` does not cover the entire place.
|
||||
// Therefore we cannot transmute, and instead we project at offset 0, which side-steps
|
||||
// the size check.
|
||||
let array_layout = self.layout_of(Ty::new_array(self.tcx.tcx, e_ty, len))?;
|
||||
assert!(array_layout.size <= mplace.layout.size);
|
||||
let mplace = mplace.offset(Size::ZERO, array_layout, self)?;
|
||||
Ok((mplace, len))
|
||||
}
|
||||
|
||||
/// Turn a local in the current frame into a place.
|
||||
pub fn local_to_place(
|
||||
&self,
|
||||
|
@ -986,7 +980,7 @@ where
|
|||
span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
|
||||
};
|
||||
let ptr = self.allocate_ptr(size, align, kind)?;
|
||||
Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout))
|
||||
Ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
|
||||
}
|
||||
|
||||
pub fn allocate(
|
||||
|
@ -1021,7 +1015,12 @@ where
|
|||
};
|
||||
let meta = Scalar::from_target_usize(u64::try_from(str.len()).unwrap(), self);
|
||||
let layout = self.layout_of(self.tcx.types.str_).unwrap();
|
||||
Ok(self.ptr_with_meta_to_mplace(ptr.into(), MemPlaceMeta::Meta(meta), layout))
|
||||
Ok(self.ptr_with_meta_to_mplace(
|
||||
ptr.into(),
|
||||
MemPlaceMeta::Meta(meta),
|
||||
layout,
|
||||
/*unaligned*/ false,
|
||||
))
|
||||
}
|
||||
|
||||
pub fn raw_const_to_mplace(
|
||||
|
|
|
@ -244,6 +244,19 @@ where
|
|||
base.offset(offset, field_layout, self)
|
||||
}
|
||||
|
||||
/// Converts a repr(simd) value into an array of the right size, such that `project_index`
|
||||
/// accesses the SIMD elements. Also returns the number of elements.
|
||||
pub fn project_to_simd<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
) -> InterpResult<'tcx, (P, u64)> {
|
||||
assert!(base.layout().ty.ty_adt_def().unwrap().repr().simd());
|
||||
// SIMD types must be newtypes around arrays, so all we have to do is project to their only field.
|
||||
let array = self.project_field(base, 0)?;
|
||||
let len = array.len(self)?;
|
||||
Ok((array, len))
|
||||
}
|
||||
|
||||
fn project_constant_index<P: Projectable<'tcx, M::Provenance>>(
|
||||
&self,
|
||||
base: &P,
|
||||
|
|
|
@ -9,7 +9,7 @@ use rustc_middle::ty::{
|
|||
};
|
||||
use tracing::debug;
|
||||
|
||||
use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
|
||||
use super::{throw_inval, InterpCx, MPlaceTy, MemoryKind};
|
||||
use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult};
|
||||
|
||||
/// Checks whether a type contains generic parameters which must be instantiated.
|
||||
|
@ -103,5 +103,5 @@ pub(crate) fn create_static_alloc<'tcx>(
|
|||
assert_eq!(ecx.machine.static_root_ids, None);
|
||||
ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
|
||||
assert!(ecx.memory.alloc_map.insert(alloc_id, (MemoryKind::Stack, alloc)).is_none());
|
||||
Ok(ecx.ptr_with_meta_to_mplace(Pointer::from(alloc_id).into(), MemPlaceMeta::None, layout))
|
||||
Ok(ecx.ptr_to_mplace(Pointer::from(alloc_id).into(), layout))
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue