diff options
| author | sinkuu <sinkuu@sinkuu.xyz> | 2017-11-06 12:35:43 +0900 |
|---|---|---|
| committer | Shotaro Yamada <sinkuu@sinkuu.xyz> | 2017-11-10 21:02:43 +0900 |
| commit | 114252410d72b63bda4eefa62df77727d1f1cc41 (patch) | |
| tree | 2b1428749a73b8281597926ece9b304d1dba5ae9 | |
| parent | ae5553d7b04d8ece340756f378b82d5e0bbb0ea2 (diff) | |
| download | rust-114252410d72b63bda4eefa62df77727d1f1cc41.tar.gz rust-114252410d72b63bda4eefa62df77727d1f1cc41.zip | |
Separately eliminate self-assignments
| -rw-r--r-- | src/librustc_mir/transform/copy_prop.rs | 43 | ||||
| -rw-r--r-- | src/librustc_mir/util/def_use.rs | 22 | ||||
| -rw-r--r-- | src/test/mir-opt/copy_propagation_arg.rs | 3 |
3 files changed, 62 insertions, 6 deletions
diff --git a/src/librustc_mir/transform/copy_prop.rs b/src/librustc_mir/transform/copy_prop.rs index 3f766629bae..a730fc30615 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/src/librustc_mir/transform/copy_prop.rs @@ -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>), diff --git a/src/librustc_mir/util/def_use.rs b/src/librustc_mir/util/def_use.rs index bd9fb4bc3cc..9ada8f2bebf 100644 --- a/src/librustc_mir/util/def_use.rs +++ b/src/librustc_mir/util/def_use.rs @@ -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 { diff --git a/src/test/mir-opt/copy_propagation_arg.rs b/src/test/mir-opt/copy_propagation_arg.rs index 8303407d2e2..ae30b5fae88 100644 --- a/src/test/mir-opt/copy_propagation_arg.rs +++ b/src/test/mir-opt/copy_propagation_arg.rs @@ -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 \ No newline at end of file +// END rustc.baz.CopyPropagation.after.mir |
