Automatically prefer integer addresses for zst MPlace
This commit is contained in:
parent
ee84c30aee
commit
cc0fbdffe7
@ -115,7 +115,7 @@ pub(super) fn op_to_const<'tcx>(
|
||||
// by-val is if we are in const_field, i.e., if this is (a field of) something that we
|
||||
// "tried to make immediate" before. We wouldn't do that for non-slice scalar pairs or
|
||||
// structs containing such.
|
||||
op.try_as_mplace()
|
||||
op.try_as_mplace(ecx)
|
||||
};
|
||||
let val = match immediate {
|
||||
Ok(mplace) => {
|
||||
@ -132,7 +132,7 @@ pub(super) fn op_to_const<'tcx>(
|
||||
// `Immediate` is when we are called from `const_field`, and that `Immediate`
|
||||
// comes from a constant so it can happen have `Undef`, because the indirect
|
||||
// memory that was read had undefined bytes.
|
||||
let mplace = op.assert_mem_place();
|
||||
let mplace = op.assert_mem_place(ecx);
|
||||
let ptr = mplace.ptr.assert_ptr();
|
||||
let alloc = ecx.tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id);
|
||||
ConstValue::ByRef { alloc, offset: ptr.offset }
|
||||
|
@ -267,7 +267,7 @@ pub fn force_op_ptr(
|
||||
&self,
|
||||
op: OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
match op.try_as_mplace() {
|
||||
match op.try_as_mplace(self) {
|
||||
Ok(mplace) => Ok(self.force_mplace_ptr(mplace)?.into()),
|
||||
Err(imm) => Ok(imm.into()), // Nothing to cast/force
|
||||
}
|
||||
@ -335,7 +335,7 @@ pub(crate) fn try_read_immediate(
|
||||
&self,
|
||||
src: OpTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, Result<ImmTy<'tcx, M::PointerTag>, MPlaceTy<'tcx, M::PointerTag>>> {
|
||||
Ok(match src.try_as_mplace() {
|
||||
Ok(match src.try_as_mplace(self) {
|
||||
Ok(mplace) => {
|
||||
if let Some(val) = self.try_read_immediate_from_mplace(mplace)? {
|
||||
Ok(val)
|
||||
@ -383,7 +383,7 @@ pub fn operand_field(
|
||||
op: OpTy<'tcx, M::PointerTag>,
|
||||
field: u64,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
let base = match op.try_as_mplace() {
|
||||
let base = match op.try_as_mplace(self) {
|
||||
Ok(mplace) => {
|
||||
// The easy case
|
||||
let field = self.mplace_field(mplace, field)?;
|
||||
@ -420,7 +420,7 @@ pub fn operand_downcast(
|
||||
variant: VariantIdx,
|
||||
) -> InterpResult<'tcx, OpTy<'tcx, M::PointerTag>> {
|
||||
// Downcasts only change the layout
|
||||
Ok(match op.try_as_mplace() {
|
||||
Ok(match op.try_as_mplace(self) {
|
||||
Ok(mplace) => self.mplace_downcast(mplace, variant)?.into(),
|
||||
Err(..) => {
|
||||
let layout = op.layout.for_variant(self, variant);
|
||||
@ -439,30 +439,10 @@ pub fn operand_projection(
|
||||
Field(field, _) => self.operand_field(base, field.index() as u64)?,
|
||||
Downcast(_, variant) => self.operand_downcast(base, variant)?,
|
||||
Deref => self.deref_operand(base)?.into(),
|
||||
ConstantIndex { .. } | Index(_) if base.layout.is_zst() => {
|
||||
OpTy {
|
||||
op: Operand::Immediate(Scalar::zst().into()),
|
||||
// the actual index doesn't matter, so we just pick a convenient one like 0
|
||||
layout: base.layout.field(self, 0)?,
|
||||
}
|
||||
}
|
||||
Subslice { from, to, from_end } if base.layout.is_zst() => {
|
||||
let elem_ty = if let ty::Array(elem_ty, _) = base.layout.ty.kind {
|
||||
elem_ty
|
||||
} else {
|
||||
bug!("slices shouldn't be zero-sized");
|
||||
};
|
||||
assert!(!from_end, "arrays shouldn't be subsliced from the end");
|
||||
|
||||
OpTy {
|
||||
op: Operand::Immediate(Scalar::zst().into()),
|
||||
layout: self.layout_of(self.tcx.mk_array(elem_ty, (to - from) as u64))?,
|
||||
}
|
||||
}
|
||||
Subslice { .. } | ConstantIndex { .. } | Index(_) => {
|
||||
// The rest should only occur as mplace, we do not use Immediates for types
|
||||
// allowing such operations. This matches place_projection forcing an allocation.
|
||||
let mplace = base.assert_mem_place();
|
||||
let mplace = base.assert_mem_place(self);
|
||||
self.mplace_projection(mplace, proj_elem)?.into()
|
||||
}
|
||||
})
|
||||
|
@ -200,16 +200,17 @@ pub(super) fn vtable(self) -> Scalar<Tag> {
|
||||
// These are defined here because they produce a place.
|
||||
impl<'tcx, Tag: ::std::fmt::Debug + Copy> OpTy<'tcx, Tag> {
|
||||
#[inline(always)]
|
||||
pub fn try_as_mplace(self) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
|
||||
pub fn try_as_mplace(self, cx: &impl HasDataLayout) -> Result<MPlaceTy<'tcx, Tag>, ImmTy<'tcx, Tag>> {
|
||||
match *self {
|
||||
Operand::Indirect(mplace) => Ok(MPlaceTy { mplace, layout: self.layout }),
|
||||
Operand::Immediate(_) if self.layout.is_zst() => Ok(MPlaceTy::dangling(self.layout, cx)),
|
||||
Operand::Immediate(imm) => Err(ImmTy { imm, layout: self.layout }),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn assert_mem_place(self) -> MPlaceTy<'tcx, Tag> {
|
||||
self.try_as_mplace().unwrap()
|
||||
pub fn assert_mem_place(self, cx: &impl HasDataLayout) -> MPlaceTy<'tcx, Tag> {
|
||||
self.try_as_mplace(cx).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,7 +306,7 @@ pub fn deref_operand(
|
||||
/// On success, returns `None` for zero-sized accesses (where nothing else is
|
||||
/// left to do) and a `Pointer` to use for the actual access otherwise.
|
||||
#[inline]
|
||||
pub fn check_mplace_access(
|
||||
pub(super) fn check_mplace_access(
|
||||
&self,
|
||||
place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
size: Option<Size>,
|
||||
@ -338,7 +339,7 @@ pub fn mplace_access_checked(
|
||||
|
||||
/// Force `place.ptr` to a `Pointer`.
|
||||
/// Can be helpful to avoid lots of `force_ptr` calls later, if this place is used a lot.
|
||||
pub fn force_mplace_ptr(
|
||||
pub(super) fn force_mplace_ptr(
|
||||
&self,
|
||||
mut place: MPlaceTy<'tcx, M::PointerTag>,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
|
||||
@ -415,7 +416,7 @@ pub fn mplace_field(
|
||||
|
||||
// Iterates over all fields of an array. Much more efficient than doing the
|
||||
// same by repeatedly calling `mplace_array`.
|
||||
pub fn mplace_array_fields(
|
||||
pub(super) fn mplace_array_fields(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, Tag>,
|
||||
) -> InterpResult<'tcx, impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Tag>>> + 'tcx>
|
||||
@ -430,7 +431,7 @@ pub fn mplace_array_fields(
|
||||
Ok((0..len).map(move |i| base.offset(i * stride, None, layout, dl)))
|
||||
}
|
||||
|
||||
pub fn mplace_subslice(
|
||||
fn mplace_subslice(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
from: u64,
|
||||
@ -471,7 +472,7 @@ pub fn mplace_subslice(
|
||||
base.offset(from_offset, meta, layout, self)
|
||||
}
|
||||
|
||||
pub fn mplace_downcast(
|
||||
pub(super) fn mplace_downcast(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
variant: VariantIdx,
|
||||
@ -482,7 +483,7 @@ pub fn mplace_downcast(
|
||||
}
|
||||
|
||||
/// Project into an mplace
|
||||
pub fn mplace_projection(
|
||||
pub(super) fn mplace_projection(
|
||||
&self,
|
||||
base: MPlaceTy<'tcx, M::PointerTag>,
|
||||
proj_elem: &mir::PlaceElem<'tcx>,
|
||||
|
@ -378,7 +378,7 @@ fn eval_fn_call(
|
||||
}
|
||||
None => {
|
||||
// Unsized self.
|
||||
args[0].assert_mem_place()
|
||||
args[0].assert_mem_place(self)
|
||||
}
|
||||
};
|
||||
// Find and consult vtable
|
||||
|
@ -571,12 +571,9 @@ fn visit_aggregate(
|
||||
) -> InterpResult<'tcx> {
|
||||
match op.layout.ty.kind {
|
||||
ty::Str => {
|
||||
let mplace = op.assert_mem_place(); // strings are never immediate
|
||||
try_validation!(
|
||||
self.ecx.read_str(mplace),
|
||||
"uninitialized or non-UTF-8 data in str",
|
||||
self.path
|
||||
);
|
||||
let mplace = op.assert_mem_place(self.ecx); // strings are never immediate
|
||||
try_validation!(self.ecx.read_str(mplace),
|
||||
"uninitialized or non-UTF-8 data in str", self.path);
|
||||
}
|
||||
ty::Array(tys, ..) | ty::Slice(tys)
|
||||
if {
|
||||
@ -604,7 +601,7 @@ fn visit_aggregate(
|
||||
return Ok(());
|
||||
}
|
||||
// non-ZST array cannot be immediate, slices are never immediate
|
||||
let mplace = op.assert_mem_place();
|
||||
let mplace = op.assert_mem_place(self.ecx);
|
||||
// This is the length of the array/slice.
|
||||
let len = mplace.len(self.ecx)?;
|
||||
// zero length slices have nothing to be checked
|
||||
|
@ -223,7 +223,7 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
|
||||
match v.layout().ty.kind {
|
||||
ty::Dynamic(..) => {
|
||||
// immediate trait objects are not a thing
|
||||
let dest = v.to_op(self.ecx())?.assert_mem_place();
|
||||
let dest = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
|
||||
let inner = self.ecx().unpack_dyn_trait(dest)?.1;
|
||||
trace!("walk_value: dyn object layout: {:#?}", inner.layout);
|
||||
// recurse with the inner type
|
||||
@ -292,13 +292,7 @@ fn walk_value(&mut self, v: Self::V) -> InterpResult<'tcx>
|
||||
},
|
||||
layout::FieldPlacement::Array { .. } => {
|
||||
// Let's get an mplace first.
|
||||
let mplace = if v.layout().is_zst() {
|
||||
// it's a ZST, the memory content cannot matter
|
||||
MPlaceTy::dangling(v.layout(), self.ecx())
|
||||
} else {
|
||||
// non-ZST array/slice/str cannot be immediate
|
||||
v.to_op(self.ecx())?.assert_mem_place()
|
||||
};
|
||||
let mplace = v.to_op(self.ecx())?.assert_mem_place(self.ecx());
|
||||
// Now we can go over all the fields.
|
||||
let iter = self.ecx().mplace_array_fields(mplace)?
|
||||
.map(|f| f.and_then(|f| {
|
||||
|
@ -707,7 +707,8 @@ fn should_const_prop(&mut self, op: OpTy<'tcx>) -> bool {
|
||||
ScalarMaybeUndef::Scalar(r),
|
||||
)) => l.is_bits() && r.is_bits(),
|
||||
interpret::Operand::Indirect(_) if mir_opt_level >= 2 => {
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, op.assert_mem_place())
|
||||
let mplace = op.assert_mem_place(&self.ecx);
|
||||
intern_const_alloc_recursive(&mut self.ecx, None, mplace)
|
||||
.expect("failed to intern alloc");
|
||||
true
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user