Skip to content

Commit d6f43a4

Browse files
Revert "Remove obsolete CallGuards MIR pass"
This reverts commit 8cee04a. It turns out that DropElaboration may need the CallGuards pass, even if trans doesn't.
1 parent ff12d78 commit d6f43a4

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

src/librustc_driver/driver.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1050,6 +1050,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10501050
// From here on out, regions are gone.
10511051
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
10521052

1053+
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
10531054
passes.push_pass(box borrowck::ElaborateDrops);
10541055
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
10551056
passes.push_pass(box mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
@@ -1061,6 +1062,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10611062
passes.push_pass(box mir::transform::copy_prop::CopyPropagation);
10621063

10631064
passes.push_pass(box mir::transform::simplify::SimplifyLocals);
1065+
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
10641066
passes.push_pass(box mir::transform::dump_mir::Marker("PreTrans"));
10651067

10661068
passes.run_passes(tcx);

src/librustc_mir/shim.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use std::fmt;
3030
use std::iter;
3131
use std::mem;
3232

33-
use transform::{no_landing_pads, simplify};
33+
use transform::{add_call_guards, no_landing_pads, simplify};
3434
use util::elaborate_drops::{self, DropElaborator, DropStyle, DropFlagMode};
3535
use util::patch::MirPatch;
3636

@@ -115,6 +115,7 @@ fn make_shim<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>,
115115
debug!("make_shim({:?}) = untransformed {:?}", instance, result);
116116
no_landing_pads::no_landing_pads(tcx, &mut result);
117117
simplify::simplify_cfg(&mut result);
118+
add_call_guards::add_call_guards(&mut result);
118119
debug!("make_shim({:?}) = {:?}", instance, result);
119120

120121
let result = tcx.alloc_mir(result);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use rustc::ty::TyCtxt;
12+
use rustc::mir::*;
13+
use rustc::mir::transform::{MirPass, MirSource, Pass};
14+
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
15+
16+
pub struct AddCallGuards;
17+
18+
/**
19+
* Breaks outgoing critical edges for call terminators in the MIR.
20+
*
21+
* Critical edges are edges that are neither the only edge leaving a
22+
* block, nor the only edge entering one.
23+
*
24+
* When you want something to happen "along" an edge, you can either
25+
* do at the end of the predecessor block, or at the start of the
26+
* successor block. Critical edges have to be broken in order to prevent
27+
* "edge actions" from affecting other edges. We need this for calls that are
28+
* translated to LLVM invoke instructions, because invoke is a block terminator
29+
* in LLVM so we can't insert any code to handle the call's result into the
30+
* block that performs the call.
31+
*
32+
* This function will break those edges by inserting new blocks along them.
33+
*
34+
* NOTE: Simplify CFG will happily undo most of the work this pass does.
35+
*
36+
*/
37+
38+
impl<'tcx> MirPass<'tcx> for AddCallGuards {
39+
fn run_pass<'a>(&mut self, _tcx: TyCtxt<'a, 'tcx, 'tcx>, _src: MirSource, mir: &mut Mir<'tcx>) {
40+
add_call_guards(mir);
41+
}
42+
}
43+
44+
pub fn add_call_guards(mir: &mut Mir) {
45+
let pred_count: IndexVec<_, _> =
46+
mir.predecessors().iter().map(|ps| ps.len()).collect();
47+
48+
// We need a place to store the new blocks generated
49+
let mut new_blocks = Vec::new();
50+
51+
let cur_len = mir.basic_blocks().len();
52+
53+
for block in mir.basic_blocks_mut() {
54+
match block.terminator {
55+
Some(Terminator {
56+
kind: TerminatorKind::Call {
57+
destination: Some((_, ref mut destination)),
58+
cleanup: Some(_),
59+
..
60+
}, source_info
61+
}) if pred_count[*destination] > 1 => {
62+
// It's a critical edge, break it
63+
let call_guard = BlockData {
64+
statements: vec![],
65+
is_cleanup: block.is_cleanup,
66+
terminator: Some(Terminator {
67+
source_info: source_info,
68+
kind: TerminatorKind::Goto { target: *destination }
69+
})
70+
};
71+
72+
// Get the index it will be when inserted into the MIR
73+
let idx = cur_len + new_blocks.len();
74+
new_blocks.push(call_guard);
75+
*destination = Block::new(idx);
76+
}
77+
_ => {}
78+
}
79+
}
80+
81+
debug!("Broke {} N edges", new_blocks.len());
82+
83+
mir.basic_blocks_mut().extend(new_blocks);
84+
}
85+
86+
impl Pass for AddCallGuards {}

src/librustc_mir/transform/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod simplify;
1313
pub mod erase_regions;
1414
pub mod no_landing_pads;
1515
pub mod type_check;
16+
pub mod add_call_guards;
1617
pub mod promote_consts;
1718
pub mod qualify_consts;
1819
pub mod dump_mir;

0 commit comments

Comments
 (0)