[const-prop] Move local storage into a Frame on InterpCx
This moves us closer to just using `InterpCx` for interpretation.
This commit is contained in:
parent
573b61ae26
commit
164ed087ab
2 changed files with 88 additions and 23 deletions
|
|
@ -319,7 +319,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
|
|||
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 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
|
|||
&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 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
|
|||
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.
|
||||
|
|
|
|||
|
|
@ -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 rustc::ty::layout::{
|
|||
};
|
||||
|
||||
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 @@ impl MirPass for ConstProp {
|
|||
|
||||
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<Local, Option<Const<'tcx>>>,
|
||||
can_const_prop: IndexVec<Local, bool>,
|
||||
param_env: ParamEnv<'tcx>,
|
||||
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
|
||||
|
|
@ -117,21 +152,28 @@ impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, '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<IndexVec<SourceScope, SourceScopeLocalData>>,
|
||||
promoted: IndexVec<Promoted, Body<'tcx>>,
|
||||
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 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
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 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn release_stolen_data(self) ->
|
||||
(ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
|
||||
IndexVec<Promoted, Body<'tcx>>)
|
||||
{
|
||||
(self.source_scope_local_data, self.promoted)
|
||||
}
|
||||
|
||||
fn get_const(&self, local: Local) -> Option<Const<'tcx>> {
|
||||
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<Const<'tcx>>) {
|
||||
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<F, T>(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue