From 485476c25a666ee89210c8ff9035836dc678547a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Mon, 27 Nov 2017 21:50:36 +0200 Subject: [PATCH] add a pass to remove no-op landing pads --- src/librustc/mir/mod.rs | 25 ++++ src/librustc_mir/transform/mod.rs | 5 + src/librustc_mir/transform/no_landing_pads.rs | 19 +-- .../transform/remove_noop_landing_pads.rs | 137 ++++++++++++++++++ 4 files changed, 169 insertions(+), 17 deletions(-) create mode 100644 src/librustc_mir/transform/remove_noop_landing_pads.rs diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 0cbd945095a9..cd4ed8081c3b 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -733,6 +733,10 @@ impl<'tcx> Terminator<'tcx> { pub fn successors_mut(&mut self) -> Vec<&mut BasicBlock> { self.kind.successors_mut() } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + self.kind.unwind_mut() + } } impl<'tcx> TerminatorKind<'tcx> { @@ -811,6 +815,27 @@ impl<'tcx> TerminatorKind<'tcx> { } } } + + pub fn unwind_mut(&mut self) -> Option<&mut Option> { + match *self { + TerminatorKind::Goto { .. } | + TerminatorKind::Resume | + TerminatorKind::Return | + TerminatorKind::Unreachable | + TerminatorKind::GeneratorDrop | + TerminatorKind::Yield { .. } | + TerminatorKind::SwitchInt { .. } | + TerminatorKind::FalseEdges { .. } => { + None + }, + TerminatorKind::Call { cleanup: ref mut unwind, .. } | + TerminatorKind::Assert { cleanup: ref mut unwind, .. } | + TerminatorKind::DropAndReplace { ref mut unwind, .. } | + TerminatorKind::Drop { ref mut unwind, .. } => { + Some(unwind) + } + } + } } impl<'tcx> BasicBlockData<'tcx> { diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs index 418d3d220581..64ba5ae3e8bd 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 dd5898cb561b..c8f171d4160c 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 000000000000..d29174d57192 --- /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 or the MIT license +// , 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); + } +}