From 525c68cf95d465a69372bf55cb75c20b2688f443 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 12:27:48 +0200 Subject: [PATCH] make StorageLive lazy as well --- src/librustc_mir/interpret/eval_context.rs | 30 +++++++++++++++------- src/librustc_mir/interpret/operand.rs | 29 +-------------------- 2 files changed, 22 insertions(+), 37 deletions(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index c3726c63ea4..05207c47d5d 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -131,6 +131,22 @@ pub enum LocalValue { Live(Operand), } +impl LocalValue { + /// 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 { + // 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> { match self.state { @@ -518,19 +534,15 @@ pub fn push_stack_frame( } }, } - // 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 @@ pub fn storage_live( 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. diff --git a/src/librustc_mir/interpret/operand.rs b/src/librustc_mir/interpret/operand.rs index 7ea56e36474..4ece062f380 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/src/librustc_mir/interpret/operand.rs @@ -14,7 +14,7 @@ }; use super::{ InterpretCx, Machine, - MemPlace, MPlaceTy, PlaceTy, Place, MemoryKind, + MemPlace, MPlaceTy, PlaceTy, Place, }; pub use rustc::mir::interpret::ScalarMaybeUndef; @@ -373,33 +373,6 @@ pub fn read_str( Ok(str) } - pub fn uninit_operand( - &mut self, - layout: TyLayout<'tcx> - ) -> EvalResult<'tcx, Operand> { - // 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, -- 2.44.0