From 114252410d72b63bda4eefa62df77727d1f1cc41 Mon Sep 17 00:00:00 2001 From: sinkuu Date: Mon, 6 Nov 2017 12:35:43 +0900 Subject: [PATCH] Separately eliminate self-assignments --- src/librustc_mir/transform/copy_prop.rs | 43 +++++++++++++++++++++--- src/librustc_mir/util/def_use.rs | 22 +++++++++++- 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 3f766629bae5..a730fc30615b 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 bd9fb4bc3cc5..9ada8f2bebf7 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>, @@ -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>, 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 8303407d2e20..ae30b5fae88f 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