Skip to content

Commit 38e9fdf

Browse files
committed
Simplify const prop checks through PlaceContext
1 parent f5e795e commit 38e9fdf

File tree

2 files changed

+52
-54
lines changed

2 files changed

+52
-54
lines changed

src/librustc/mir/interpret/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ pub struct Allocation {
171171
/// The alignment of the allocation to detect unaligned reads.
172172
pub align: Align,
173173
/// Whether the allocation (of a static) should be put into mutable memory when translating
174-
///
174+
///
175175
/// Only happens for `static mut` or `static` with interior mutability
176176
pub runtime_mutability: Mutability,
177177
}

src/librustc_mir/transform/const_prop.rs

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
1717
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
18-
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp};
19-
use rustc::mir::visit::Visitor;
18+
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, BorrowKind};
19+
use rustc::mir::visit::{Visitor, PlaceContext};
2020
use rustc::ty::layout::LayoutOf;
2121
use rustc::middle::const_val::ConstVal;
2222
use rustc::ty::{TyCtxt, self, Instance};
@@ -64,11 +64,16 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
6464
tcx: TyCtxt<'a, 'tcx, 'tcx>,
6565
source: MirSource,
6666
) -> OptimizationFinder<'b, 'a, 'tcx> {
67+
let can_const_prop = CanConstProp::check(
68+
mir,
69+
tcx,
70+
tcx.param_env(source.def_id),
71+
);
6772
OptimizationFinder {
6873
mir,
6974
tcx,
7075
source,
71-
can_const_prop: CanConstProp::check(mir),
76+
can_const_prop,
7277
places: IndexVec::from_elem(None, &mir.local_decls),
7378
}
7479
}
@@ -272,78 +277,71 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
272277
(tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
273278
}
274279

275-
struct CanConstProp {
280+
struct CanConstProp<'b, 'a, 'tcx:'a+'b> {
276281
can_const_prop: IndexVec<Local, bool>,
277282
// false at the beginning, once set, there are not allowed to be any more assignments
278283
found_assignment: IndexVec<Local, bool>,
284+
mir: &'b Mir<'tcx>,
285+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
286+
param_env: ty::ParamEnv<'tcx>,
279287
}
280288

281-
impl CanConstProp {
289+
impl<'b, 'a, 'tcx:'b> CanConstProp<'b, 'a, 'tcx> {
282290
/// returns true if `local` can be propagated
283-
fn check<'tcx>(mir: &Mir<'tcx>) -> IndexVec<Local, bool> {
291+
fn check(
292+
mir: &'b Mir<'tcx>,
293+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
294+
param_env: ty::ParamEnv<'tcx>,
295+
) -> IndexVec<Local, bool> {
284296
let mut cpv = CanConstProp {
285297
can_const_prop: IndexVec::from_elem(true, &mir.local_decls),
286298
found_assignment: IndexVec::from_elem(false, &mir.local_decls),
299+
mir,
300+
tcx,
301+
param_env,
287302
};
288303
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
289-
*val = mir.local_kind(local) == LocalKind::Temp;
304+
*val = mir.local_kind(local) != LocalKind::Arg;
290305
}
291306
cpv.visit_mir(mir);
292307
cpv.can_const_prop
293308
}
294309
}
295310

296-
fn place_to_local(mut place: &Place) -> Option<Local> {
297-
while let Place::Projection(ref proj) = place {
298-
place = &proj.base;
299-
}
300-
if let Place::Local(local) = *place {
301-
Some(local)
302-
} else {
303-
None
304-
}
305-
}
306-
307-
impl<'tcx> Visitor<'tcx> for CanConstProp {
308-
fn visit_statement(
311+
impl<'a, 'b, 'tcx> Visitor<'tcx> for CanConstProp<'a, 'b, 'tcx> {
312+
fn visit_local(
309313
&mut self,
310-
block: BasicBlock,
311-
statement: &Statement<'tcx>,
312-
location: Location,
314+
&local: &Local,
315+
context: PlaceContext<'tcx>,
316+
_: Location,
313317
) {
314-
self.super_statement(block, statement, location);
315-
match statement.kind {
316-
StatementKind::SetDiscriminant { ref place, .. } |
317-
StatementKind::Assign(ref place, _) => {
318-
if let Some(local) = place_to_local(place) {
319-
if self.found_assignment[local] {
320-
self.can_const_prop[local] = false;
321-
} else {
322-
self.found_assignment[local] = true
323-
}
324-
}
318+
use rustc::mir::visit::PlaceContext::*;
319+
match context {
320+
// Constants must have at most one write
321+
// FIXME(oli-obk): we could be more powerful here, if the multiple writes
322+
// only occur in independent execution paths
323+
Store => if self.found_assignment[local] {
324+
self.can_const_prop[local] = false;
325+
} else {
326+
self.found_assignment[local] = true
325327
},
326-
StatementKind::InlineAsm { ref outputs, .. } => {
327-
for place in outputs {
328-
if let Some(local) = place_to_local(place) {
329-
if self.found_assignment[local] {
330-
self.can_const_prop[local] = false;
331-
} else {
332-
self.found_assignment[local] = true
333-
}
334-
return;
335-
}
328+
// Reading constants is allowed an arbitrary number of times
329+
Copy | Move |
330+
StorageDead | StorageLive |
331+
Validate |
332+
Inspect => {},
333+
Borrow { kind: BorrowKind::Shared, .. } => {
334+
// cannot const prop immutable borrows of types with interior mutability
335+
let has_interior_mutability = self
336+
.mir
337+
.local_decls[local]
338+
.ty
339+
.is_freeze(self.tcx, self.param_env, self.mir.span);
340+
if has_interior_mutability {
341+
self.can_const_prop[local] = false;
336342
}
337343
}
338-
_ => {}
339-
}
340-
}
341-
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
342-
self.super_rvalue(rvalue, location);
343-
if let Rvalue::Ref(_, _, ref place) = *rvalue {
344-
if let Some(local) = place_to_local(place) {
345-
self.can_const_prop[local] = false;
346-
}
344+
_ => self.can_const_prop[local] = false,
347345
}
348346
}
349347
}

0 commit comments

Comments
 (0)