Skip to content

Commit 166c49d

Browse files
committed
Auto merge of #62012 - wesleywiser:const_prop_use_ecx, r=oli-obk
Use ecx for const-prop local storage r? @oli-obk
2 parents 3cc3486 + c686130 commit 166c49d

File tree

2 files changed

+116
-25
lines changed

2 files changed

+116
-25
lines changed

src/librustc_mir/interpret/eval_context.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
319319
t: T,
320320
) -> InterpResult<'tcx, T> {
321321
match self.stack.last() {
322-
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)),
322+
Some(frame) => Ok(self.monomorphize_with_substs(t, frame.instance.substs)?),
323323
None => if t.needs_subst() {
324324
err!(TooGeneric).into()
325325
} else {
@@ -332,11 +332,16 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
332332
&self,
333333
t: T,
334334
substs: SubstsRef<'tcx>
335-
) -> T {
335+
) -> InterpResult<'tcx, T> {
336336
// miri doesn't care about lifetimes, and will choke on some crazy ones
337337
// let's simply get rid of them
338338
let substituted = t.subst(*self.tcx, substs);
339-
self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted)
339+
340+
if substituted.needs_subst() {
341+
return err!(TooGeneric);
342+
}
343+
344+
Ok(self.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), substituted))
340345
}
341346

342347
pub fn layout_of_local(
@@ -349,7 +354,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> InterpretCx<'mir, 'tcx, M> {
349354
None => {
350355
let layout = crate::interpret::operand::from_known_layout(layout, || {
351356
let local_ty = frame.body.local_decls[local].ty;
352-
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs);
357+
let local_ty = self.monomorphize_with_substs(local_ty, frame.instance.substs)?;
353358
self.layout_of(local_ty)
354359
})?;
355360
// Layouts of locals are requested a lot, so we cache them.

src/librustc_mir/transform/const_prop.rs

+107-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
//! Propagates constants for early reporting of statically known
22
//! assertion failures
33
4+
use std::cell::Cell;
5+
46
use rustc::hir::def::DefKind;
57
use rustc::mir::{
68
AggregateKind, Constant, Location, Place, PlaceBase, Body, Operand, Rvalue,
@@ -21,7 +23,8 @@ use rustc::ty::layout::{
2123
};
2224

2325
use crate::interpret::{
24-
self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy, ImmTy, MemoryKind,
26+
self, InterpretCx, ScalarMaybeUndef, Immediate, OpTy,
27+
ImmTy, MemoryKind, StackPopCleanup, LocalValue, LocalState,
2528
};
2629
use crate::const_eval::{
2730
CompileTimeInterpreter, error_to_const_error, eval_promoted, mk_eval_cx,
@@ -56,21 +59,54 @@ impl MirPass for ConstProp {
5659

5760
trace!("ConstProp starting for {:?}", source.def_id());
5861

62+
// Steal some data we need from `body`.
63+
let source_scope_local_data = std::mem::replace(
64+
&mut body.source_scope_local_data,
65+
ClearCrossCrate::Clear
66+
);
67+
let promoted = std::mem::replace(
68+
&mut body.promoted,
69+
IndexVec::new()
70+
);
71+
72+
let dummy_body =
73+
&Body::new(
74+
body.basic_blocks().clone(),
75+
Default::default(),
76+
ClearCrossCrate::Clear,
77+
Default::default(),
78+
None,
79+
body.local_decls.clone(),
80+
Default::default(),
81+
body.arg_count,
82+
Default::default(),
83+
tcx.def_span(source.def_id()),
84+
Default::default(),
85+
);
86+
5987
// FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold
6088
// constants, instead of just checking for const-folding succeeding.
6189
// That would require an uniform one-def no-mutation analysis
6290
// and RPO (or recursing when needing the value of a local).
63-
let mut optimization_finder = ConstPropagator::new(body, tcx, source);
91+
let mut optimization_finder = ConstPropagator::new(
92+
body,
93+
dummy_body,
94+
source_scope_local_data,
95+
promoted,
96+
tcx,
97+
source
98+
);
6499
optimization_finder.visit_body(body);
65100

66101
// put back the data we stole from `mir`
102+
let (source_scope_local_data, promoted) = optimization_finder.release_stolen_data();
67103
std::mem::replace(
68104
&mut body.source_scope_local_data,
69-
optimization_finder.source_scope_local_data
105+
source_scope_local_data
70106
);
71107
std::mem::replace(
72108
&mut body.promoted,
73-
optimization_finder.promoted
109+
promoted
74110
);
75111

76112
trace!("ConstProp done for {:?}", source.def_id());
@@ -84,7 +120,6 @@ struct ConstPropagator<'mir, 'tcx> {
84120
ecx: InterpretCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>>,
85121
tcx: TyCtxt<'tcx>,
86122
source: MirSource<'tcx>,
87-
places: IndexVec<Local, Option<Const<'tcx>>>,
88123
can_const_prop: IndexVec<Local, bool>,
89124
param_env: ParamEnv<'tcx>,
90125
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
@@ -117,36 +152,87 @@ impl<'mir, 'tcx> HasTyCtxt<'tcx> for ConstPropagator<'mir, 'tcx> {
117152

118153
impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
119154
fn new(
120-
body: &mut Body<'tcx>,
155+
body: &Body<'tcx>,
156+
dummy_body: &'mir Body<'tcx>,
157+
source_scope_local_data: ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
158+
promoted: IndexVec<Promoted, Body<'tcx>>,
121159
tcx: TyCtxt<'tcx>,
122160
source: MirSource<'tcx>,
123161
) -> ConstPropagator<'mir, 'tcx> {
124-
let param_env = tcx.param_env(source.def_id());
125-
let ecx = mk_eval_cx(tcx, tcx.def_span(source.def_id()), param_env);
162+
let def_id = source.def_id();
163+
let param_env = tcx.param_env(def_id);
164+
let span = tcx.def_span(def_id);
165+
let mut ecx = mk_eval_cx(tcx, span, param_env);
126166
let can_const_prop = CanConstProp::check(body);
127-
let source_scope_local_data = std::mem::replace(
128-
&mut body.source_scope_local_data,
129-
ClearCrossCrate::Clear
130-
);
131-
let promoted = std::mem::replace(
132-
&mut body.promoted,
133-
IndexVec::new()
134-
);
167+
168+
ecx.push_stack_frame(
169+
Instance::new(def_id, &InternalSubsts::identity_for_item(tcx, def_id)),
170+
span,
171+
dummy_body,
172+
None,
173+
StackPopCleanup::None {
174+
cleanup: false,
175+
},
176+
).expect("failed to push initial stack frame");
135177

136178
ConstPropagator {
137179
ecx,
138180
tcx,
139181
source,
140182
param_env,
141183
can_const_prop,
142-
places: IndexVec::from_elem(None, &body.local_decls),
143184
source_scope_local_data,
144185
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
145186
local_decls: body.local_decls.clone(),
146187
promoted,
147188
}
148189
}
149190

191+
fn release_stolen_data(
192+
self,
193+
) -> (
194+
ClearCrossCrate<IndexVec<SourceScope, SourceScopeLocalData>>,
195+
IndexVec<Promoted, Body<'tcx>>,
196+
) {
197+
(self.source_scope_local_data, self.promoted)
198+
}
199+
200+
fn get_const(&self, local: Local) -> Option<Const<'tcx>> {
201+
let l = &self.ecx.frame().locals[local];
202+
203+
// If the local is `Unitialized` or `Dead` then we haven't propagated a value into it.
204+
//
205+
// `InterpretCx::access_local()` mostly takes care of this for us however, for ZSTs,
206+
// it will synthesize a value for us. In doing so, that will cause the
207+
// `get_const(l).is_empty()` assert right before we call `set_const()` in `visit_statement`
208+
// to fail.
209+
if let LocalValue::Uninitialized | LocalValue::Dead = l.value {
210+
return None;
211+
}
212+
213+
self.ecx.access_local(self.ecx.frame(), local, None).ok()
214+
}
215+
216+
fn set_const(&mut self, local: Local, c: Const<'tcx>) {
217+
let frame = self.ecx.frame_mut();
218+
219+
if let Some(layout) = frame.locals[local].layout.get() {
220+
debug_assert_eq!(c.layout, layout);
221+
}
222+
223+
frame.locals[local] = LocalState {
224+
value: LocalValue::Live(*c),
225+
layout: Cell::new(Some(c.layout)),
226+
};
227+
}
228+
229+
fn remove_const(&mut self, local: Local) {
230+
self.ecx.frame_mut().locals[local] = LocalState {
231+
value: LocalValue::Uninitialized,
232+
layout: Cell::new(None),
233+
};
234+
}
235+
150236
fn use_ecx<F, T>(
151237
&mut self,
152238
source_info: SourceInfo,
@@ -296,7 +382,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
296382
trace!("eval_place(place={:?})", place);
297383
place.iterate(|place_base, place_projection| {
298384
let mut eval = match place_base {
299-
PlaceBase::Local(loc) => self.places[*loc].clone()?,
385+
PlaceBase::Local(loc) => self.get_const(*loc).clone()?,
300386
PlaceBase::Static(box Static {kind: StaticKind::Promoted(promoted), ..}) => {
301387
let generics = self.tcx.generics_of(self.source.def_id());
302388
if generics.requires_monomorphization(self.tcx) {
@@ -699,8 +785,8 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
699785
trace!("checking whether {:?} can be stored to {:?}", value, local);
700786
if self.can_const_prop[local] {
701787
trace!("storing {:?} to {:?}", value, local);
702-
assert!(self.places[local].is_none());
703-
self.places[local] = Some(value);
788+
assert!(self.get_const(local).is_none());
789+
self.set_const(local, value);
704790

705791
if self.should_const_prop() {
706792
self.replace_with_const(
@@ -740,7 +826,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
740826
place = &proj.base;
741827
}
742828
if let Place::Base(PlaceBase::Local(local)) = *place {
743-
self.places[local] = None;
829+
self.remove_const(local);
744830
}
745831
},
746832
Operand::Constant(_) => {}

0 commit comments

Comments
 (0)