about summary refs log tree commit diff
path: root/src/librustc_mir/transform
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2017-11-27 21:50:36 +0200
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-12-03 02:47:44 +0200
commit485476c25a666ee89210c8ff9035836dc678547a (patch)
treeb5876e5f75a49b1fc3d101d060ef96b06bd7e62f /src/librustc_mir/transform
parent25416c70814eb64a8cdd709af7aba1833832bebf (diff)
downloadrust-485476c25a666ee89210c8ff9035836dc678547a.tar.gz
rust-485476c25a666ee89210c8ff9035836dc678547a.zip
add a pass to remove no-op landing pads
Diffstat (limited to 'src/librustc_mir/transform')
-rw-r--r--src/librustc_mir/transform/mod.rs5
-rw-r--r--src/librustc_mir/transform/no_landing_pads.rs19
-rw-r--r--src/librustc_mir/transform/remove_noop_landing_pads.rs137
3 files changed, 144 insertions, 17 deletions
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index 418d3d22058..64ba5ae3e8b 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -36,6 +36,7 @@ pub mod elaborate_drops;
 pub mod add_call_guards;
 pub mod promote_consts;
 pub mod qualify_consts;
+pub mod remove_noop_landing_pads;
 pub mod dump_mir;
 pub mod deaggregator;
 pub mod instcombine;
@@ -226,8 +227,11 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
 
     let mut mir = tcx.mir_validated(def_id).steal();
     run_passes![tcx, mir, def_id, 2;
+        // Remove all things not needed by analysis
         no_landing_pads::NoLandingPads,
         simplify_branches::SimplifyBranches::new("initial"),
+        remove_noop_landing_pads::RemoveNoopLandingPads,
+        simplify::SimplifyCfg::new("early-opt"),
 
         // These next passes must be executed together
         add_call_guards::CriticalCallEdges,
@@ -255,6 +259,7 @@ fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx
         instcombine::InstCombine,
         deaggregator::Deaggregator,
         copy_prop::CopyPropagation,
+        remove_noop_landing_pads::RemoveNoopLandingPads,
         simplify::SimplifyLocals,
 
         generator::StateTransform,
diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/src/librustc_mir/transform/no_landing_pads.rs
index dd5898cb561..c8f171d4160 100644
--- a/src/librustc_mir/transform/no_landing_pads.rs
+++ b/src/librustc_mir/transform/no_landing_pads.rs
@@ -38,23 +38,8 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
                         bb: BasicBlock,
                         terminator: &mut Terminator<'tcx>,
                         location: Location) {
-        match terminator.kind {
-            TerminatorKind::Goto { .. } |
-            TerminatorKind::Resume |
-            TerminatorKind::Return |
-            TerminatorKind::Unreachable |
-            TerminatorKind::GeneratorDrop |
-            TerminatorKind::Yield { .. } |
-            TerminatorKind::SwitchInt { .. } |
-            TerminatorKind::FalseEdges { .. } => {
-                /* nothing to do */
-            },
-            TerminatorKind::Call { cleanup: ref mut unwind, .. } |
-            TerminatorKind::Assert { cleanup: ref mut unwind, .. } |
-            TerminatorKind::DropAndReplace { ref mut unwind, .. } |
-            TerminatorKind::Drop { ref mut unwind, .. } => {
-                unwind.take();
-            },
+        if let Some(unwind) = terminator.kind.unwind_mut() {
+            unwind.take();
         }
         self.super_terminator(bb, terminator, location);
     }
diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/src/librustc_mir/transform/remove_noop_landing_pads.rs
new file mode 100644
index 00000000000..d29174d5719
--- /dev/null
+++ b/src/librustc_mir/transform/remove_noop_landing_pads.rs
@@ -0,0 +1,137 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use rustc::ty::TyCtxt;
+use rustc::mir::*;
+use rustc_data_structures::bitvec::BitVector;
+use rustc_data_structures::indexed_vec::Idx;
+use transform::{MirPass, MirSource};
+use util::patch::MirPatch;
+
+/// A pass that removes no-op landing pads and replaces jumps to them with
+/// `None`. This is important because otherwise LLVM generates terrible
+/// code for these.
+pub struct RemoveNoopLandingPads;
+
+impl MirPass for RemoveNoopLandingPads {
+    fn run_pass<'a, 'tcx>(&self,
+                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                          _src: MirSource,
+                          mir: &mut Mir<'tcx>) {
+        if tcx.sess.no_landing_pads() {
+            return
+        }
+
+        debug!("remove_noop_landing_pads({:?})", mir);
+        self.remove_nop_landing_pads(mir);
+    }
+}
+
+impl RemoveNoopLandingPads {
+    fn is_nop_landing_pad(&self, bb: BasicBlock, mir: &Mir, nop_landing_pads: &BitVector)
+                          -> bool
+    {
+        for stmt in &mir[bb].statements {
+            match stmt.kind {
+                StatementKind::StorageLive(_) |
+                StatementKind::StorageDead(_) |
+                StatementKind::EndRegion(_) |
+                StatementKind::Nop => {
+                    // These are all nops in a landing pad (there's some
+                    // borrowck interaction between EndRegion and storage
+                    // instructions, but this should all run after borrowck).
+                }
+
+                StatementKind::Assign(Place::Local(_), Rvalue::Use(_)) => {
+                    // Writing to a local (e.g. a drop flag) does not
+                    // turn a landing pad to a non-nop
+                }
+
+                StatementKind::Assign(_, _) |
+                StatementKind::SetDiscriminant { .. } |
+                StatementKind::InlineAsm { .. } |
+                StatementKind::Validate { .. } => {
+                    return false;
+                }
+            }
+        }
+
+        let terminator = mir[bb].terminator();
+        match terminator.kind {
+            TerminatorKind::Goto { .. } |
+            TerminatorKind::Resume |
+            TerminatorKind::SwitchInt { .. } |
+            TerminatorKind::FalseEdges { .. } => {
+                terminator.successors().iter().all(|succ| {
+                    nop_landing_pads.contains(succ.index())
+                })
+            },
+            TerminatorKind::GeneratorDrop |
+            TerminatorKind::Yield { .. } |
+            TerminatorKind::Return |
+            TerminatorKind::Unreachable |
+            TerminatorKind::Call { .. } |
+            TerminatorKind::Assert { .. } |
+            TerminatorKind::DropAndReplace { .. } |
+            TerminatorKind::Drop { .. } => {
+                false
+            }
+        }
+    }
+
+    fn remove_nop_landing_pads(&self, mir: &mut Mir) {
+        // make sure there's a single resume block
+        let resume_block = {
+            let patch = MirPatch::new(mir);
+            let resume_block = patch.resume_block();
+            patch.apply(mir);
+            resume_block
+        };
+        debug!("remove_noop_landing_pads: resume block is {:?}", resume_block);
+
+        let mut jumps_folded = 0;
+        let mut landing_pads_removed = 0;
+        let mut nop_landing_pads = BitVector::new(mir.basic_blocks().len());
+
+        // This is a post-order traversal, so that if A post-dominates B
+        // then A will be visited before B.
+        let postorder: Vec<_> = traversal::postorder(mir).map(|(bb, _)| bb).collect();
+        for bb in postorder {
+            debug!("  processing {:?}", bb);
+            for target in mir[bb].terminator_mut().successors_mut() {
+                if *target != resume_block && nop_landing_pads.contains(target.index()) {
+                    debug!("    folding noop jump to {:?} to resume block", target);
+                    *target = resume_block;
+                    jumps_folded += 1;
+                }
+            }
+
+            match mir[bb].terminator_mut().unwind_mut() {
+                Some(unwind) => {
+                    if *unwind == Some(resume_block) {
+                        debug!("    removing noop landing pad");
+                        jumps_folded -= 1;
+                        landing_pads_removed += 1;
+                        *unwind = None;
+                    }
+                }
+                _ => {}
+            }
+
+            let is_nop_landing_pad = self.is_nop_landing_pad(bb, mir, &nop_landing_pads);
+            if is_nop_landing_pad {
+                nop_landing_pads.insert(bb.index());
+            }
+            debug!("    is_nop_landing_pad({:?}) = {}", bb, is_nop_landing_pad);
+        }
+
+        debug!("removed {:?} jumps and {:?} landing pads", jumps_folded, landing_pads_removed);
+    }
+}