From: Wesley Wiser Date: Fri, 14 Jun 2019 00:20:14 +0000 (-0400) Subject: [const-prop] Move local storage into a `Frame` on `InterpCx` X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=164ed087abe2c0e99270326b7fd6f3c93548903f;p=rust.git [const-prop] Move local storage into a `Frame` on `InterpCx` This moves us closer to just using `InterpCx` for interpretation. --- diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 4afa4a0cbb3..fbba8d10326 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -319,7 +319,7 @@ pub(super) fn monomorphize + Subst<'tcx>>( t: T, ) -> InterpResult<'tcx, T> { match self.stack.last() { - Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)), + Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?), None => if t.needs_subst() { err!(TooGeneric).into() } else { @@ -332,11 +332,16 @@ fn monomorphize_with_substs + Subst<'tcx>>( &self, t: T, substs: SubstsRef<'tcx> - ) -> T { + ) -> InterpResult<'tcx, T> { // miri doesn't care about lifetimes, and will choke on some crazy ones // let's simply get rid of them let substituted = t.subst(*self.tcx, substs); - self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted) + + if substituted.needs_subst() { + return err!(TooGeneric); + } + + Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)) } pub fn layout_of_local( @@ -349,7 +354,7 @@ pub fn layout_of_local( None => { let layout = crate::interpret::operand::from_known_layout(layout, || { let local_ty = frame.body.local_decls[local].ty; - let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs); + let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?; self.layout_of(local_ty) })?; // Layouts of locals are requested a lot, so we cache them. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 830f8239a09..1471e15baa5 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -1,6 +1,8 @@ //! Propagates constants for early reporting of statically known //! assertion failures +use std::cell::Cell; + use rustc::hir::def::DefKind; use rustc::mir::{ AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue, @@ -21,7 +23,8 @@ }; use crate::interpret::{ - self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind, + self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, + ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState, }; use crate::const_eval::{ CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx, @@ -56,21 +59,54 @@ fn run_pass<'tcx>(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut trace!("ConstProp starting for {:?}", source.def_id()); + // steal some data we need from `body` + let source_scope_local_data = std::mem::replace( + &mut body.source_scope_local_data, + ClearCrossCrate::Clear + ); + let promoted = std::mem::replace( + &mut body.promoted, + IndexVec::new() + ); + + let dummy_body = + &Body::new( + body.basic_blocks().clone(), + Default::default(), + ClearCrossCrate::Clear, + Default::default(), + None, + body.local_decls.clone(), + Default::default(), + body.arg_count, + Default::default(), + tcx.def_span(source.def_id()), + Default::default(), + ); + // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold // constants, instead of just checking for const-folding succeeding. // That would require an uniform one-def no-mutation analysis // and RPO (or recursing when needing the value of a local). - let mut optimization_finder = ConstPropagator::new(body, tcx, source); + let mut optimization_finder = ConstPropagator::new( + body, + dummy_body, + source_scope_local_data, + promoted, + tcx, + source + ); optimization_finder.visit_body(body); // put back the data we stole from `mir` + let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data(); std::mem::replace( &mut body.source_scope_local_data, - optimization_finder.source_scope_local_data + source_scope_local_data ); std::mem::replace( &mut body.promoted, - optimization_finder.promoted + promoted ); trace!("ConstProp done for {:?}", source.def_id()); @@ -84,7 +120,6 @@ struct ConstPropagator<'mir, 'tcx> { ecx: InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, - places: IndexVec>>, can_const_prop: IndexVec, param_env: ParamEnv<'tcx>, source_scope_local_data: ClearCrossCrate>, @@ -117,21 +152,28 @@ fn tcx(&self) -> TyCtxt<'tcx> { impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { fn new( - body: &mut Body<'tcx>, + body: &Body<'tcx>, + dummy_body: &'mir Body<'tcx>, + source_scope_local_data: ClearCrossCrate>, + promoted: IndexVec>, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, ) -> ConstPropagator<'mir, 'tcx> { - let param_env = tcx.param_env(source.def_id()); - let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env); + let def_id = source.def_id(); + let param_env = tcx.param_env(def_id); + let span = tcx.def_span(def_id); + let mut ecx = mk_eval_cx(tcx, span, param_env); let can_const_prop = CanConstProp::check(body); - let source_scope_local_data = std::mem::replace( - &mut body.source_scope_local_data, - ClearCrossCrate::Clear - ); - let promoted = std::mem::replace( - &mut body.promoted, - IndexVec::new() - ); + + ecx.push_stack_frame( + Instance::new(def_id, &InternalSubsts::identity_for_item(tcx, def_id)), + span, + dummy_body, + None, + StackPopCleanup::None { + cleanup: false, + }, + ).expect("failed to push initial stack frame"); ConstPropagator { ecx, @@ -139,7 +181,6 @@ fn new( source, param_env, can_const_prop, - places: IndexVec::from_elem(None, &body.local_decls), source_scope_local_data, //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it local_decls: body.local_decls.clone(), @@ -147,12 +188,31 @@ fn new( } } + fn release_stolen_data(self) -> + (ClearCrossCrate>, + IndexVec>) + { + (self.source_scope_local_data, self.promoted) + } + fn get_const(&self, local: Local) -> Option> { - self.places[local] + let l = &self.ecx.frame().locals[local]; + if l.value == LocalValue::Uninitialized || l.value == LocalValue::Dead { + return None; + } + + self.ecx.access_local(self.ecx.frame(), local, None).ok() } fn set_const(&mut self, local: Local, c: Option>) { - self.places[local] = c; + self.ecx.frame_mut().locals[local] = + match c { + Some(op_ty) => LocalState { + value: LocalValue::Live(*op_ty), + layout: Cell::new(Some(op_ty.layout)), + }, + None => LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }, + }; } fn use_ecx(