make StorageLive lazy as well

This commit is contained in:
Ralf Jung 2019-04-07 12:27:48 +02:00
parent cb51f872a8
commit 525c68cf95
2 changed files with 22 additions and 37 deletions

View file

@ -131,6 +131,22 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
Live(Operand<Tag, Id>),
}
impl<Tag: Copy> LocalValue<Tag> {
/// The initial value of a local: ZST get "initialized" because they can be read from without
/// ever having been written to.
fn uninit_local(
layout: TyLayout<'_>
) -> LocalValue<Tag> {
// FIXME: Can we avoid this ZST special case? That would likely require MIR
// generation changes.
if layout.is_zst() {
LocalValue::Live(Operand::Immediate(Immediate::Scalar(Scalar::zst().into())))
} else {
LocalValue::Uninitialized
}
}
}
impl<'tcx, Tag: Copy> LocalState<'tcx, Tag> {
pub fn access(&self) -> EvalResult<'tcx, &Operand<Tag>> {
match self.state {
@ -518,19 +534,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
}
},
}
// FIXME: We initialize live ZST here. This should not be needed if MIR was
// consistently generated for ZST, but that seems to not be the case -- there
// is MIR (around promoteds in particular) that reads local ZSTs that never
// were written to.
// The remaining locals are uninitialized, fill them with `uninit_local`.
// (For ZST this is not a NOP.)
for (idx, local) in locals.iter_enumerated_mut() {
match local.state {
LocalValue::Uninitialized => {
// This needs to be properly initialized.
let ty = self.monomorphize(mir.local_decls[idx].ty)?;
let layout = self.layout_of(ty)?;
if layout.is_zst() {
local.state = LocalValue::Live(self.uninit_operand(layout)?);
}
local.state = LocalValue::uninit_local(layout);
local.layout = Cell::new(Some(layout));
}
LocalValue::Dead => {
@ -622,9 +634,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
trace!("{:?} is now live", local);
let layout = self.layout_of_local(self.frame(), local, None)?;
let init = LocalValue::Live(self.uninit_operand(layout)?);
let local_val = LocalValue::uninit_local(layout);
// StorageLive *always* kills the value that's currently stored
Ok(mem::replace(&mut self.frame_mut().locals[local].state, init))
Ok(mem::replace(&mut self.frame_mut().locals[local].state, local_val))
}
/// Returns the old value of the local.

View file

@ -14,7 +14,7 @@ use rustc::mir::interpret::{
};
use super::{
InterpretCx, Machine,
MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind,
MemPlace, MPlaceTy, PlaceTy, Place,
};
pub use rustc::mir::interpret::ScalarMaybeUndef;
@ -373,33 +373,6 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tcx, M>
Ok(str)
}
pub fn uninit_operand(
&mut self,
layout: TyLayout<'tcx>
) -> EvalResult<'tcx, Operand<M::PointerTag>> {
// This decides which types we will use the Immediate optimization for, and hence should
// match what `try_read_immediate` and `eval_place_to_op` support.
if layout.is_zst() {
return Ok(Operand::Immediate(Immediate::Scalar(Scalar::zst().into())));
}
Ok(match layout.abi {
layout::Abi::Scalar(..) =>
Operand::Immediate(Immediate::Scalar(ScalarMaybeUndef::Undef)),
layout::Abi::ScalarPair(..) =>
Operand::Immediate(Immediate::ScalarPair(
ScalarMaybeUndef::Undef,
ScalarMaybeUndef::Undef,
)),
_ => {
trace!("Forcing allocation for local of type {:?}", layout.ty);
Operand::Indirect(
*self.allocate(layout, MemoryKind::Stack)
)
}
})
}
/// Projection functions
pub fn operand_field(
&self,