Separately eliminate self-assignments

This commit is contained in:
sinkuu 2017-11-06 12:35:43 +09:00 committed by Shotaro Yamada
parent ae5553d7b0
commit 114252410d
3 changed files with 62 additions and 6 deletions

View file

@ -69,10 +69,14 @@ impl MirPass for CopyPropagation {
return;
}
let mut def_use_analysis = DefUseAnalysis::new(mir);
loop {
let mut def_use_analysis = DefUseAnalysis::new(mir);
def_use_analysis.analyze(mir);
if eliminate_self_assignments(mir, &def_use_analysis) {
def_use_analysis.analyze(mir);
}
let mut changed = false;
for dest_local in mir.local_decls.indices() {
debug!("Considering destination local: {:?}", dest_local);
@ -106,9 +110,7 @@ impl MirPass for CopyPropagation {
dest_local);
continue;
}
let dest_lvalue_def = dest_use_info.defs_and_uses.iter().filter(|lvalue_def| {
lvalue_def.context.is_mutating_use() && !lvalue_def.context.is_drop()
}).next().unwrap();
let dest_lvalue_def = dest_use_info.defs_not_including_drop().next().unwrap();
location = dest_lvalue_def.location;
let basic_block = &mir[location.block];
@ -158,6 +160,39 @@ impl MirPass for CopyPropagation {
}
}
fn eliminate_self_assignments<'tcx>(
mir: &mut Mir<'tcx>,
def_use_analysis: &DefUseAnalysis<'tcx>,
) -> bool {
let mut changed = false;
for dest_local in mir.local_decls.indices() {
let dest_use_info = def_use_analysis.local_info(dest_local);
for def in dest_use_info.defs_not_including_drop() {
let location = def.location;
if let Some(stmt) = mir[location.block].statements.get(location.statement_index) {
match stmt.kind {
StatementKind::Assign(
Lvalue::Local(local),
Rvalue::Use(Operand::Consume(Lvalue::Local(src_local))),
) if local == dest_local && dest_local == src_local => {}
_ => {
continue;
}
}
} else {
continue;
}
debug!("Deleting a self-assignment for {:?}", dest_local);
mir.make_statement_nop(location);
changed = true;
}
}
changed
}
enum Action<'tcx> {
PropagateLocalCopy(Local),
PropagateConstant(Constant<'tcx>),

View file

@ -15,6 +15,8 @@ use rustc::mir::visit::{LvalueContext, MutVisitor, Visitor};
use rustc_data_structures::indexed_vec::IndexVec;
use std::marker::PhantomData;
use std::mem;
use std::slice;
use std::iter;
pub struct DefUseAnalysis<'tcx> {
info: IndexVec<Local, Info<'tcx>>,
@ -39,6 +41,8 @@ impl<'tcx> DefUseAnalysis<'tcx> {
}
pub fn analyze(&mut self, mir: &Mir<'tcx>) {
self.clear();
let mut finder = DefUseFinder {
info: mem::replace(&mut self.info, IndexVec::new()),
};
@ -46,6 +50,12 @@ impl<'tcx> DefUseAnalysis<'tcx> {
self.info = finder.info
}
fn clear(&mut self) {
for info in &mut self.info {
info.clear();
}
}
pub fn local_info(&self, local: Local) -> &Info<'tcx> {
&self.info[local]
}
@ -93,14 +103,24 @@ impl<'tcx> Info<'tcx> {
}
}
fn clear(&mut self) {
self.defs_and_uses.clear();
}
pub fn def_count(&self) -> usize {
self.defs_and_uses.iter().filter(|lvalue_use| lvalue_use.context.is_mutating_use()).count()
}
pub fn def_count_not_including_drop(&self) -> usize {
self.defs_not_including_drop().count()
}
pub fn defs_not_including_drop(
&self,
) -> iter::Filter<slice::Iter<Use<'tcx>>, fn(&&Use<'tcx>) -> bool> {
self.defs_and_uses.iter().filter(|lvalue_use| {
lvalue_use.context.is_mutating_use() && !lvalue_use.context.is_drop()
}).count()
})
}
pub fn use_count(&self) -> usize {

View file

@ -34,6 +34,7 @@ fn main() {
// Make sure the function actually gets instantiated.
foo(0);
bar(0);
baz(0);
}
// END RUST SOURCE
@ -112,4 +113,4 @@ fn main() {
// _0 = ();
// return;
// }
// END rustc.baz.CopyPropagation.after.mir
// END rustc.baz.CopyPropagation.after.mir