use rustc_index::bit_set::BitSet;
use rustc_index::vec::{Idx, IndexVec};
-use rustc::ty::TyCtxt;
+use rustc::ty::{self, TyCtxt};
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, Visitor, PlaceContext, MutatingUseContext};
-use rustc::session::config::DebugInfo;
use std::borrow::Cow;
use crate::transform::{MirPass, MirSource};
}
}
-pub fn simplify_cfg(body: &mut Body<'_>) {
+pub fn simplify_cfg(body: &mut BodyAndCache<'_>) {
CfgSimplifier::new(body).simplify();
remove_dead_blocks(body);
Cow::Borrowed(&self.label)
}
- fn run_pass(&self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(
+ &self, _tcx: TyCtxt<'tcx>, _src: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
+ ) {
debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body);
simplify_cfg(body);
}
}
impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
- pub fn new(body: &'a mut Body<'tcx>) -> Self {
+ pub fn new(body: &'a mut BodyAndCache<'tcx>) -> Self {
let mut pred_count = IndexVec::from_elem(0u32, body.basic_blocks());
// we can't use mir.predecessors() here because that counts
changed |= inner_changed;
}
- self.basic_blocks[bb].statements.extend(new_stmts);
- self.basic_blocks[bb].terminator = Some(terminator);
+ let data = &mut self.basic_blocks[bb];
+ data.statements.extend(new_stmts);
+ data.terminator = Some(terminator);
changed |= inner_changed;
}
}
}
-pub fn remove_dead_blocks(body: &mut Body<'_>) {
+pub fn remove_dead_blocks(body: &mut BodyAndCache<'_>) {
let mut seen = BitSet::new_empty(body.basic_blocks().len());
for (bb, _) in traversal::preorder(body) {
seen.insert(bb.index());
for alive_index in seen.iter() {
replacements[alive_index] = BasicBlock::new(used_blocks);
if alive_index != used_blocks {
- // Swap the next alive block data with the current available slot. Since alive_index is
- // non-decreasing this is a valid operation.
+ // Swap the next alive block data with the current available slot. Since
+ // alive_index is non-decreasing this is a valid operation.
basic_blocks.raw.swap(alive_index, used_blocks);
}
used_blocks += 1;
pub struct SimplifyLocals;
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
- fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) {
+ fn run_pass(
+ &self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut BodyAndCache<'tcx>
+ ) {
trace!("running SimplifyLocals on {:?}", source);
let locals = {
+ let read_only_cache = read_only!(body);
let mut marker = DeclMarker {
locals: BitSet::new_empty(body.local_decls.len()),
body,
};
- marker.visit_body(body);
+ marker.visit_body(read_only_cache);
// Return pointer and arguments are always live
marker.locals.insert(RETURN_PLACE);
for arg in body.args_iter() {
marker.locals.insert(arg);
}
- // We may need to keep dead user variables live for debuginfo.
- if tcx.sess.opts.debuginfo == DebugInfo::Full {
- for local in body.vars_iter() {
- marker.locals.insert(local);
- }
- }
-
marker.locals
};
// Ignore stores of constants because `ConstProp` and `CopyProp` can remove uses of many
// of these locals. However, if the local is still needed, then it will be referenced in
// another place and we'll mark it as being used there.
- if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) {
- let stmt =
- &self.body.basic_blocks()[location.block].statements[location.statement_index];
- if let StatementKind::Assign(box (p, Rvalue::Use(Operand::Constant(c)))) = &stmt.kind {
- match c.literal.val {
- // Keep assignments from unevaluated constants around, since the evaluation
- // may report errors, even if the use of the constant is dead code.
- interpret::ConstValue::Unevaluated(..) => {}
- _ => if p.as_local().is_some() {
- trace!("skipping store of const value {:?} to {:?}", c, p);
- return;
- },
+ if ctx == PlaceContext::MutatingUse(MutatingUseContext::Store) ||
+ ctx == PlaceContext::MutatingUse(MutatingUseContext::Projection) {
+ let block = &self.body.basic_blocks()[location.block];
+ if location.statement_index != block.statements.len() {
+ let stmt =
+ &block.statements[location.statement_index];
+
+ if let StatementKind::Assign(
+ box (p, Rvalue::Use(Operand::Constant(c)))
+ ) = &stmt.kind {
+ match c.literal.val {
+ // Keep assignments from unevaluated constants around, since the evaluation
+ // may report errors, even if the use of the constant is dead code.
+ ty::ConstKind::Unevaluated(..) => {}
+ _ => if !p.is_indirect() {
+ trace!("skipping store of const value {:?} to {:?}", c, p);
+ return;
+ },
+ }
}
}
}
self.map[*l].is_some()
}
StatementKind::Assign(box (place, _)) => {
- if let Some(local) = place.as_local() {
+ if let PlaceBase::Local(local) = place.base {
self.map[local].is_some()
} else {
true