Skip to content

Commit 81f738c

Browse files
committed
---
yaml --- r: 272241 b: refs/heads/auto c: eee7f3c h: refs/heads/master i: 272239: 0770fd9
1 parent 7e479c9 commit 81f738c

File tree

6 files changed

+228
-43
lines changed

6 files changed

+228
-43
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
88
refs/tags/release-0.3.1: 495bae036dfe5ec6ceafd3312b4dca48741e845b
99
refs/tags/release-0.4: e828ea2080499553b97dfe33b3f4d472b4562ad7
1010
refs/tags/release-0.5: 7e3bcfbf21278251ee936ad53e92e9b719702d73
11-
refs/heads/auto: 60a28e60aa6eb0ed074fa5e6875e60cb2f038605
11+
refs/heads/auto: eee7f3c73298ed77f61ad15cdca552528d6f3783
1212
refs/tags/release-0.6: b4ebcfa1812664df5e142f0134a5faea3918544c
1313
refs/tags/0.1: b19db808c2793fe2976759b85a355c3ad8c8b336
1414
refs/tags/0.2: 1754d02027f2924bed83b0160ee340c7f41d5ea1

branches/auto/src/librustc_driver/driver.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -932,7 +932,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
932932

933933
/// Run the translation phase to LLVM, after which the AST and analysis can
934934
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
935-
mir_map: MirMap<'tcx>,
935+
mut mir_map: MirMap<'tcx>,
936936
analysis: ty::CrateAnalysis)
937937
-> trans::CrateTranslation {
938938
let time_passes = tcx.sess.time_passes();
@@ -941,6 +941,13 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
941941
"resolving dependency formats",
942942
|| dependency_format::calculate(&tcx.sess));
943943

944+
time(time_passes,
945+
"erasing regions from MIR",
946+
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));
947+
948+
time(time_passes, "breaking critical edges",
949+
|| mir::transform::break_critical_edges::break_critical_edges(&mut mir_map));
950+
944951
// Option dance to work around the lack of stack once closures.
945952
time(time_passes,
946953
"translation",
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
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+
use std::mem;
11+
12+
use rustc_back::slice;
13+
use rustc::mir::repr::*;
14+
use rustc::mir::mir_map::MirMap;
15+
16+
use traversal;
17+
18+
/**
19+
* Breaks critical edges 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.
28+
*
29+
* This function will break those edges by inserting new blocks along them.
30+
*
31+
* A special case is Drop and Call terminators with unwind/cleanup successors,
32+
* They use `invoke` in LLVM, which terminates a block, meaning that code cannot
33+
* be inserted after them, so even if an edge is the only edge leaving a block
34+
* like that, we still insert blocks if the edge is one of many entering the
35+
* target.
36+
*
37+
* NOTE: Simplify CFG will happily undo most of the work this pass does.
38+
*
39+
*/
40+
pub fn break_critical_edges<'tcx>(mir_map: &mut MirMap<'tcx>) {
41+
for (_, mir) in &mut mir_map.map {
42+
break_critical_edges_fn(mir);
43+
}
44+
}
45+
46+
/*
47+
* Predecessor map for tracking the predecessors of a block
48+
*/
49+
struct PredMap {
50+
preds: Vec<BlockPredecessors>
51+
}
52+
53+
/**
54+
* Most blocks only have one predecessor, so we can cut down on
55+
* some allocation by not using Vec until we have more than one.
56+
*/
57+
#[derive(Clone)]
58+
enum BlockPredecessors {
59+
None,
60+
One(BasicBlock),
61+
Some(Vec<BasicBlock>)
62+
}
63+
64+
impl PredMap {
65+
pub fn new(n: usize) -> PredMap {
66+
let preds = vec![BlockPredecessors::None; n];
67+
68+
PredMap {
69+
preds: preds
70+
}
71+
}
72+
73+
fn ensure_len(&mut self, bb: BasicBlock) {
74+
let idx = bb.index();
75+
while self.preds.len() <= idx {
76+
self.preds.push(BlockPredecessors::None);
77+
}
78+
}
79+
80+
pub fn add_pred(&mut self, target: BasicBlock, pred: BasicBlock) {
81+
self.ensure_len(target);
82+
83+
let preds = mem::replace(&mut self.preds[target.index()], BlockPredecessors::None);
84+
match preds {
85+
BlockPredecessors::None => {
86+
self.preds[target.index()] = BlockPredecessors::One(pred);
87+
}
88+
BlockPredecessors::One(bb) => {
89+
self.preds[target.index()] = BlockPredecessors::Some(vec![bb, pred]);
90+
}
91+
BlockPredecessors::Some(mut preds) => {
92+
preds.push(pred);
93+
self.preds[target.index()] = BlockPredecessors::Some(preds);
94+
}
95+
}
96+
}
97+
98+
pub fn remove_pred(&mut self, target: BasicBlock, pred: BasicBlock) {
99+
self.ensure_len(target);
100+
101+
let preds = mem::replace(&mut self.preds[target.index()], BlockPredecessors::None);
102+
match preds {
103+
BlockPredecessors::None => {}
104+
BlockPredecessors::One(bb) if bb == pred => {}
105+
106+
BlockPredecessors::One(bb) => {
107+
self.preds[target.index()] = BlockPredecessors::One(bb);
108+
}
109+
110+
BlockPredecessors::Some(mut preds) => {
111+
preds.retain(|&bb| bb != pred);
112+
self.preds[target.index()] = BlockPredecessors::Some(preds);
113+
}
114+
}
115+
}
116+
117+
pub fn get_preds(&self, bb: BasicBlock) -> &[BasicBlock] {
118+
match self.preds[bb.index()] {
119+
BlockPredecessors::None => &[],
120+
BlockPredecessors::One(ref bb) => slice::ref_slice(bb),
121+
BlockPredecessors::Some(ref bbs) => &bbs[..]
122+
}
123+
}
124+
}
125+
126+
127+
fn break_critical_edges_fn(mir: &mut Mir) {
128+
let mut pred_map = PredMap::new(mir.basic_blocks.len());
129+
130+
// Build the precedecessor map for the MIR
131+
for (pred, data) in traversal::preorder(mir) {
132+
if let Some(ref term) = data.terminator {
133+
for &tgt in term.successors().iter() {
134+
pred_map.add_pred(tgt, pred);
135+
}
136+
}
137+
}
138+
139+
// We need a place to store the new blocks generated
140+
let mut new_blocks = Vec::new();
141+
142+
let bbs = mir.all_basic_blocks();
143+
let cur_len = mir.basic_blocks.len();
144+
145+
for &bb in &bbs {
146+
let data = mir.basic_block_data_mut(bb);
147+
148+
if let Some(ref mut term) = data.terminator {
149+
let is_invoke = term_is_invoke(term);
150+
let succs = term.successors_mut();
151+
if succs.len() > 1 || (succs.len() > 0 && is_invoke) {
152+
for tgt in succs {
153+
let num_preds = pred_map.get_preds(*tgt).len();
154+
if num_preds > 1 {
155+
// It's a critical edge, break it
156+
let goto = Terminator::Goto { target: *tgt };
157+
let data = BasicBlockData::new(Some(goto));
158+
// Get the index it will be when inserted into the MIR
159+
let idx = cur_len + new_blocks.len();
160+
new_blocks.push(data);
161+
*tgt = BasicBlock::new(idx);
162+
}
163+
}
164+
}
165+
}
166+
}
167+
168+
debug!("Broke {} N edges", new_blocks.len());
169+
170+
mir.basic_blocks.extend_from_slice(&new_blocks);
171+
}
172+
173+
// Returns true if the terminator would use an invoke in LLVM.
174+
fn term_is_invoke(term: &Terminator) -> bool {
175+
match *term {
176+
Terminator::Call { cleanup: Some(_), .. } |
177+
Terminator::Drop { unwind: Some(_), .. } => true,
178+
_ => false
179+
}
180+
}

branches/auto/src/librustc_mir/transform/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ pub mod simplify_cfg;
1313
pub mod erase_regions;
1414
pub mod no_landing_pads;
1515
pub mod type_check;
16+
pub mod break_critical_edges;

branches/auto/src/librustc_trans/mir/block.rs

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -300,33 +300,8 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
300300

301301
// Many different ways to call a function handled here
302302
if let Some(cleanup) = cleanup.map(|bb| self.bcx(bb)) {
303-
// We translate the copy into a temporary block. The temporary block is
304-
// necessary because the current block has already been terminated (by
305-
// `invoke`) and we cannot really translate into the target block
306-
// because:
307-
// * The target block may have more than a single precedesor;
308-
// * Some LLVM insns cannot have a preceeding store insn (phi,
309-
// cleanuppad), and adding/prepending the store now may render
310-
// those other instructions invalid.
311-
//
312-
// NB: This approach still may break some LLVM code. For example if the
313-
// target block starts with a `phi` (which may only match on immediate
314-
// precedesors), it cannot know about this temporary block thus
315-
// resulting in an invalid code:
316-
//
317-
// this:
318-
// …
319-
// %0 = …
320-
// %1 = invoke to label %temp …
321-
// temp:
322-
// store ty %1, ty* %dest
323-
// br label %actualtargetblock
324-
// actualtargetblock: ; preds: %temp, …
325-
// phi … [%this, …], [%0, …] ; ERROR: phi requires to match only on
326-
// ; immediate precedesors
327-
328-
let ret_bcx = if destination.is_some() {
329-
self.fcx.new_block("", None)
303+
let ret_bcx = if let Some((_, target)) = *destination {
304+
self.blocks[target.index()]
330305
} else {
331306
self.unreachable_block()
332307
};
@@ -343,15 +318,16 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
343318
self.set_operand_dropped(bcx, op);
344319
});
345320

346-
if let Some((_, target)) = *destination {
321+
if destination.is_some() {
347322
let ret_bcx = ret_bcx.build();
348-
if let Some(ret_dest) = ret_dest {
349-
fn_ty.ret.store(&ret_bcx, invokeret, ret_dest.llval);
350-
}
351-
for op in args {
352-
self.set_operand_dropped(&ret_bcx, op);
353-
}
354-
ret_bcx.br(self.llblock(target));
323+
ret_bcx.at_start(|ret_bcx| {
324+
if let Some(ret_dest) = ret_dest {
325+
fn_ty.ret.store(&ret_bcx, invokeret, ret_dest.llval);
326+
}
327+
for op in args {
328+
self.set_operand_dropped(&ret_bcx, op);
329+
}
330+
});
355331
}
356332
} else {
357333
let llret = bcx.call(fn_ptr, &llargs, cleanup_bundle.as_ref());

branches/auto/src/librustc_trans/mir/mod.rs

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,11 @@ use common::{self, Block, BlockAndBuilder, FunctionContext};
1919
use std::ops::Deref;
2020
use std::rc::Rc;
2121

22+
use rustc_data_structures::bitvec::BitVector;
23+
2224
use self::lvalue::{LvalueRef, get_dataptr, get_meta};
2325
use rustc_mir::traversal;
2426

25-
use self::lvalue::LvalueRef;
2627
use self::operand::OperandRef;
2728

2829
#[derive(Clone)]
@@ -98,7 +99,7 @@ enum TempRef<'tcx> {
9899

99100
///////////////////////////////////////////////////////////////////////////
100101

101-
pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
102+
pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
102103
let bcx = fcx.init(false, None).build();
103104
let mir = bcx.mir();
104105

@@ -135,8 +136,13 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
135136
let block_bcxs: Vec<Block<'blk,'tcx>> =
136137
mir_blocks.iter()
137138
.map(|&bb|{
138-
// FIXME(#30941) this doesn't handle msvc-style exceptions
139-
fcx.new_block(&format!("{:?}", bb), None)
139+
if bb == mir::START_BLOCK {
140+
fcx.new_block("start", None)
141+
} else if bb == mir::END_BLOCK {
142+
fcx.new_block("end", None)
143+
} else {
144+
fcx.new_block(&format!("{:?}", bb), None)
145+
}
140146
})
141147
.collect();
142148

@@ -145,7 +151,7 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
145151
bcx.br(start_bcx.llbb);
146152

147153
let mut mircx = MirContext {
148-
mir: mir,
154+
mir: mir.clone(),
149155
fcx: fcx,
150156
llpersonalityslot: None,
151157
blocks: block_bcxs,
@@ -155,13 +161,28 @@ pub fn trans_mir<'blk, 'tcx>(fcx: &'blk FunctionContext<'blk, 'tcx>) {
155161
args: args,
156162
};
157163

158-
let rpo = traversal::reverse_postorder(mir);
164+
let mut visited = BitVector::new(mir_blocks.len());
165+
166+
let rpo = traversal::reverse_postorder(&mir);
159167
// Translate the body of each block using reverse postorder
160168
for (bb, _) in rpo {
169+
visited.insert(bb.index());
161170
mircx.trans_block(bb);
162171
}
163172

173+
// Add unreachable instructions at the end of unreachable blocks
174+
// so they're actually terminated.
175+
// TODO: Remove the blocks from the function
176+
for &bb in &mir_blocks {
177+
if !visited.contains(bb.index()) {
178+
mircx.blocks[bb.index()].build().unreachable();
179+
}
180+
}
181+
182+
164183
fcx.cleanup();
184+
185+
debug!("trans_mir: {:?}", ::trans::value::Value(fcx.llfn));
165186
}
166187

167188
/// Produce, for each argument, a `ValueRef` pointing at the

0 commit comments

Comments
 (0)