Simplify const prop checks through PlaceContext

This commit is contained in:
Oliver Schneider 2018-01-30 13:57:13 +01:00
parent 65ed591197
commit 57ae890265
No known key found for this signature in database
GPG Key ID: A69F8D225B3AD7D9
2 changed files with 53 additions and 55 deletions

View File

@ -171,7 +171,7 @@ pub struct Allocation {
/// The alignment of the allocation to detect unaligned reads. /// The alignment of the allocation to detect unaligned reads.
pub align: Align, pub align: Align,
/// Whether the allocation (of a static) should be put into mutable memory when translating /// Whether the allocation (of a static) should be put into mutable memory when translating
/// ///
/// Only happens for `static mut` or `static` with interior mutability /// Only happens for `static mut` or `static` with interior mutability
pub runtime_mutability: Mutability, pub runtime_mutability: Mutability,
} }

View File

@ -15,8 +15,8 @@
use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local}; use rustc::mir::{Constant, Literal, Location, Place, Mir, Operand, Rvalue, Local};
use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind}; use rustc::mir::{NullOp, StatementKind, Statement, BasicBlock, LocalKind};
use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp}; use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, BorrowKind};
use rustc::mir::visit::Visitor; use rustc::mir::visit::{Visitor, PlaceContext};
use rustc::ty::layout::LayoutOf; use rustc::ty::layout::LayoutOf;
use rustc::middle::const_val::ConstVal; use rustc::middle::const_val::ConstVal;
use rustc::ty::{TyCtxt, self, Instance}; use rustc::ty::{TyCtxt, self, Instance};
@ -64,11 +64,16 @@ impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
tcx: TyCtxt<'a, 'tcx, 'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>,
source: MirSource, source: MirSource,
) -> OptimizationFinder<'b, 'a, 'tcx> { ) -> OptimizationFinder<'b, 'a, 'tcx> {
let can_const_prop = CanConstProp::check(
mir,
tcx,
tcx.param_env(source.def_id),
);
OptimizationFinder { OptimizationFinder {
mir, mir,
tcx, tcx,
source, source,
can_const_prop: CanConstProp::check(mir), can_const_prop,
places: IndexVec::from_elem(None, &mir.local_decls), places: IndexVec::from_elem(None, &mir.local_decls),
} }
} }
@ -272,78 +277,71 @@ fn type_size_of<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
(tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes()) (tcx, param_env).layout_of(ty).ok().map(|layout| layout.size.bytes())
} }
struct CanConstProp { struct CanConstProp<'b, 'a, 'tcx:'a+'b> {
can_const_prop: IndexVec<Local, bool>, can_const_prop: IndexVec<Local, bool>,
// false at the beginning, once set, there are not allowed to be any more assignments // false at the beginning, once set, there are not allowed to be any more assignments
found_assignment: IndexVec<Local, bool>, found_assignment: IndexVec<Local, bool>,
mir: &'b Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
} }
impl CanConstProp { impl<'b, 'a, 'tcx:'b> CanConstProp<'b, 'a, 'tcx> {
/// returns true if `local` can be propagated /// returns true if `local` can be propagated
fn check<'tcx>(mir: &Mir<'tcx>) -> IndexVec<Local, bool> { fn check(
mir: &'b Mir<'tcx>,
tcx: TyCtxt<'a, 'tcx, 'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> IndexVec<Local, bool> {
let mut cpv = CanConstProp { let mut cpv = CanConstProp {
can_const_prop: IndexVec::from_elem(true, &mir.local_decls), can_const_prop: IndexVec::from_elem(true, &mir.local_decls),
found_assignment: IndexVec::from_elem(false, &mir.local_decls), found_assignment: IndexVec::from_elem(false, &mir.local_decls),
mir,
tcx,
param_env,
}; };
for (local, val) in cpv.can_const_prop.iter_enumerated_mut() { for (local, val) in cpv.can_const_prop.iter_enumerated_mut() {
*val = mir.local_kind(local) == LocalKind::Temp; *val = mir.local_kind(local) != LocalKind::Arg;
} }
cpv.visit_mir(mir); cpv.visit_mir(mir);
cpv.can_const_prop cpv.can_const_prop
} }
} }
fn place_to_local(mut place: &Place) -> Option<Local> { impl<'a, 'b, 'tcx> Visitor<'tcx> for CanConstProp<'a, 'b, 'tcx> {
while let Place::Projection(ref proj) = place { fn visit_local(
place = &proj.base;
}
if let Place::Local(local) = *place {
Some(local)
} else {
None
}
}
impl<'tcx> Visitor<'tcx> for CanConstProp {
fn visit_statement(
&mut self, &mut self,
block: BasicBlock, &local: &Local,
statement: &Statement<'tcx>, context: PlaceContext<'tcx>,
location: Location, _: Location,
) { ) {
self.super_statement(block, statement, location); use rustc::mir::visit::PlaceContext::*;
match statement.kind { match context {
StatementKind::SetDiscriminant { ref place, .. } | // Constants must have at most one write
StatementKind::Assign(ref place, _) => { // FIXME(oli-obk): we could be more powerful here, if the multiple writes
if let Some(local) = place_to_local(place) { // only occur in independent execution paths
if self.found_assignment[local] { Store => if self.found_assignment[local] {
self.can_const_prop[local] = false;
} else {
self.found_assignment[local] = true
}
}
},
StatementKind::InlineAsm { ref outputs, .. } => {
for place in outputs {
if let Some(local) = place_to_local(place) {
if self.found_assignment[local] {
self.can_const_prop[local] = false;
} else {
self.found_assignment[local] = true
}
return;
}
}
}
_ => {}
}
}
fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
self.super_rvalue(rvalue, location);
if let Rvalue::Ref(_, _, ref place) = *rvalue {
if let Some(local) = place_to_local(place) {
self.can_const_prop[local] = false; self.can_const_prop[local] = false;
} else {
self.found_assignment[local] = true
},
// Reading constants is allowed an arbitrary number of times
Copy | Move |
StorageDead | StorageLive |
Validate |
Inspect => {},
Borrow { kind: BorrowKind::Shared, .. } => {
// cannot const prop immutable borrows of types with interior mutability
let has_interior_mutability = self
.mir
.local_decls[local]
.ty
.is_freeze(self.tcx, self.param_env, self.mir.span);
if has_interior_mutability {
self.can_const_prop[local] = false;
}
} }
_ => self.can_const_prop[local] = false,
} }
} }
} }