Add a no-landing-pads MIR pass

The pass removes the unwind branch of each terminator, thus moving the responsibility of handling
the -Z no-landing-pads flag to a small self-contained pass… instead of polluting the translator.
This commit is contained in:
Simonas Kazlauskas 2016-02-11 10:13:35 +02:00
parent 1de70d33f7
commit 5ad4673a40
4 changed files with 59 additions and 8 deletions

View file

@ -22,7 +22,7 @@ extern crate rustc_front;
use build;
use graphviz;
use pretty;
use transform::simplify_cfg;
use transform::{simplify_cfg, no_landing_pads};
use rustc::dep_graph::DepNode;
use rustc::mir::repr::Mir;
use hair::cx::Cx;
@ -148,6 +148,10 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
Ok(mut mir) => {
// FIXME: This should run later rather than earlier (since this is supposed to be a
// codegen option), but we do not want to re-run the whole simplify_cfg pass all
// over again after this pass.
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, self.tcx);
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);
let meta_item_list = self.attr

View file

@ -10,4 +10,5 @@
pub mod simplify_cfg;
pub mod erase_regions;
pub mod no_landing_pads;
mod util;

View file

@ -0,0 +1,47 @@
// Copyright 2015 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.
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
//! specified.
use rustc::middle::ty;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::MirPass;
pub struct NoLandingPads;
impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
fn visit_terminator(&mut self, bb: BasicBlock, terminator: &mut Terminator<'tcx>) {
match *terminator {
Terminator::Goto { .. } |
Terminator::Resume |
Terminator::Return |
Terminator::If { .. } |
Terminator::Switch { .. } |
Terminator::SwitchInt { .. } => { /* nothing to do */ },
Terminator::Drop { ref mut unwind, .. } => {
unwind.take();
},
Terminator::Call { ref mut cleanup, .. } => {
cleanup.take();
},
}
self.super_terminator(bb, terminator);
}
}
impl MirPass for NoLandingPads {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
if tcx.sess.no_landing_pads() {
self.visit_mir(mir);
}
}
}

View file

@ -180,11 +180,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}
let avoid_invoke = bcx.with_block(|bcx| base::avoid_invoke(bcx));
// Many different ways to call a function handled here
match (is_foreign, avoid_invoke, cleanup, destination) {
match (is_foreign, cleanup, destination) {
// The two cases below are the only ones to use LLVMs `invoke`.
(false, false, &Some(cleanup), &None) => {
(false, &Some(cleanup), &None) => {
let cleanup = self.bcx(cleanup);
let landingpad = self.make_landing_pad(cleanup);
let unreachable_blk = self.unreachable_block();
@ -195,7 +194,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
None,
Some(attrs));
},
(false, false, &Some(cleanup), &Some((_, success))) => {
(false, &Some(cleanup), &Some((_, success))) => {
let cleanup = self.bcx(cleanup);
let landingpad = self.make_landing_pad(cleanup);
let (target, postinvoke) = if must_copy_dest {
@ -242,11 +241,11 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
target.br(postinvoketarget.llbb());
}
},
(false, _, _, &None) => {
(false, _, &None) => {
bcx.call(callee.immediate(), &llargs[..], None, Some(attrs));
bcx.unreachable();
}
(false, _, _, &Some((_, target))) => {
(false, _, &Some((_, target))) => {
let llret = bcx.call(callee.immediate(),
&llargs[..],
None,
@ -261,7 +260,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx.br(self.llblock(target));
}
// Foreign functions
(true, _, _, destination) => {
(true, _, destination) => {
let (dest, _) = ret_dest_ty
.expect("return destination is not set");
bcx = bcx.map_block(|bcx| {