Skip to content

Commit 4106ab2

Browse files
committed
break critical edges only when needed
the *only* place where critical edges need to be broken is on Call instructions, so only break them there.
1 parent 4248269 commit 4106ab2

File tree

5 files changed

+87
-77
lines changed

5 files changed

+87
-77
lines changed

src/librustc_borrowck/borrowck/mir/elaborate_drops.rs

+28-32
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,30 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
327327
let data = self.mir.basic_block_data(bb);
328328
let terminator = data.terminator();
329329

330-
let unwind = Some(unwind.unwrap_or_else(|| {
331-
// we can't use the resume block directly, because we
332-
// may want to add a drop flag write.
333-
self.jump_to_resume_block(terminator.scope,
334-
terminator.span)
335-
}));
330+
let assign = Statement {
331+
kind: StatementKind::Assign(location.clone(), Rvalue::Use(value.clone())),
332+
span: terminator.span,
333+
scope: terminator.scope
334+
};
335+
336+
let unwind = unwind.unwrap_or(self.patch.resume_block());
337+
let unwind = self.patch.new_block(BasicBlockData {
338+
statements: vec![assign.clone()],
339+
terminator: Some(Terminator {
340+
kind: TerminatorKind::Goto { target: unwind },
341+
..*terminator
342+
}),
343+
is_cleanup: true
344+
});
345+
346+
let target = self.patch.new_block(BasicBlockData {
347+
statements: vec![assign],
348+
terminator: Some(Terminator {
349+
kind: TerminatorKind::Goto { target: target },
350+
..*terminator
351+
}),
352+
is_cleanup: data.is_cleanup,
353+
});
336354

337355
if !self.lvalue_is_tracked(location) {
338356
// drop and replace behind a pointer/array/whatever. The location
@@ -341,7 +359,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
341359
self.patch.patch_terminator(bb, TerminatorKind::Drop {
342360
location: location.clone(),
343361
target: target,
344-
unwind: unwind
362+
unwind: Some(unwind)
345363
});
346364
} else {
347365
debug!("elaborate_drop_and_replace({:?}) - tracked", terminator);
@@ -356,24 +374,15 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
356374
lvalue: location,
357375
path: path,
358376
succ: target,
359-
unwind: unwind
377+
unwind: Some(unwind)
360378
}, bb);
361379
on_all_children_bits(self.tcx, self.mir, self.move_data(), path, |child| {
362380
self.set_drop_flag(Location { block: target, index: 0 },
363381
child, DropFlagState::Present);
364-
if let Some(unwind) = unwind {
365-
self.set_drop_flag(Location { block: unwind, index: 0 },
366-
child, DropFlagState::Present);
367-
}
382+
self.set_drop_flag(Location { block: unwind, index: 0 },
383+
child, DropFlagState::Present);
368384
});
369385
}
370-
371-
self.patch.add_assign(Location { block: target, index: 0 },
372-
location.clone(), Rvalue::Use(value.clone()));
373-
if let Some(unwind) = unwind {
374-
self.patch.add_assign(Location { block: unwind, index: 0 },
375-
location.clone(), Rvalue::Use(value.clone()));
376-
}
377386
}
378387

379388
/// This elaborates a single drop instruction, located at `bb`, and
@@ -828,19 +837,6 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
828837
})
829838
}
830839

831-
fn jump_to_resume_block<'a>(&mut self, scope: ScopeId, span: Span) -> BasicBlock {
832-
let resume_block = self.patch.resume_block();
833-
self.patch.new_block(BasicBlockData {
834-
statements: vec![],
835-
terminator: Some(Terminator {
836-
scope: scope, span: span, kind: TerminatorKind::Goto {
837-
target: resume_block
838-
}
839-
}),
840-
is_cleanup: true
841-
})
842-
}
843-
844840
fn box_free_block<'a>(
845841
&mut self,
846842
c: &DropCtxt<'a, 'tcx>,

src/librustc_driver/driver.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -1032,11 +1032,12 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10321032
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
10331033
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
10341034
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
1035-
passes.push_pass(box mir::transform::break_cleanup_edges::BreakCleanupEdges);
1035+
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
10361036
passes.push_pass(box borrowck::ElaborateDrops);
10371037
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
10381038
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
1039-
passes.push_pass(box mir::transform::break_cleanup_edges::BreakCleanupEdges);
1039+
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
1040+
passes.push_pass(box mir::transform::dump_mir::DumpMir("pre_trans"));
10401041
passes.run_passes(tcx, &mut mir_map);
10411042
});
10421043

src/librustc_mir/transform/break_cleanup_edges.rs src/librustc_mir/transform/add_call_guards.rs

+27-42
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,11 @@ use rustc::ty::TyCtxt;
1212
use rustc::mir::repr::*;
1313
use rustc::mir::transform::{MirPass, MirSource, Pass};
1414

15-
use rustc_data_structures::bitvec::BitVector;
16-
1715
use pretty;
1816

1917
use traversal;
2018

21-
pub struct BreakCleanupEdges;
19+
pub struct AddCallGuards;
2220

2321
/**
2422
* Breaks outgoing critical edges for call terminators in the MIR.
@@ -40,7 +38,7 @@ pub struct BreakCleanupEdges;
4038
*
4139
*/
4240

43-
impl<'tcx> MirPass<'tcx> for BreakCleanupEdges {
41+
impl<'tcx> MirPass<'tcx> for AddCallGuards {
4442
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
4543
let mut pred_count = vec![0u32; mir.basic_blocks.len()];
4644

@@ -53,9 +51,6 @@ impl<'tcx> MirPass<'tcx> for BreakCleanupEdges {
5351
}
5452
}
5553

56-
let cleanup_map : BitVector = mir.basic_blocks
57-
.iter().map(|bb| bb.is_cleanup).collect();
58-
5954
// We need a place to store the new blocks generated
6055
let mut new_blocks = Vec::new();
6156

@@ -65,30 +60,31 @@ impl<'tcx> MirPass<'tcx> for BreakCleanupEdges {
6560
for &bb in &bbs {
6661
let data = mir.basic_block_data_mut(bb);
6762

68-
if let Some(ref mut term) = data.terminator {
69-
if term_is_invoke(term) {
70-
let term_span = term.span;
71-
let term_scope = term.scope;
72-
let succs = term.successors_mut();
73-
for tgt in succs {
74-
let num_preds = pred_count[tgt.index()];
75-
if num_preds > 1 {
76-
// It's a critical edge, break it
77-
let goto = Terminator {
78-
span: term_span,
79-
scope: term_scope,
80-
kind: TerminatorKind::Goto { target: *tgt }
81-
};
82-
let mut data = BasicBlockData::new(Some(goto));
83-
data.is_cleanup = cleanup_map.contains(tgt.index());
84-
85-
// Get the index it will be when inserted into the MIR
86-
let idx = cur_len + new_blocks.len();
87-
new_blocks.push(data);
88-
*tgt = BasicBlock::new(idx);
89-
}
90-
}
63+
match data.terminator {
64+
Some(Terminator {
65+
kind: TerminatorKind::Call {
66+
destination: Some((_, ref mut destination)),
67+
cleanup: Some(_),
68+
..
69+
}, span, scope
70+
}) if pred_count[destination.index()] > 1 => {
71+
// It's a critical edge, break it
72+
let call_guard = BasicBlockData {
73+
statements: vec![],
74+
is_cleanup: data.is_cleanup,
75+
terminator: Some(Terminator {
76+
span: span,
77+
scope: scope,
78+
kind: TerminatorKind::Goto { target: *destination }
79+
})
80+
};
81+
82+
// Get the index it will be when inserted into the MIR
83+
let idx = cur_len + new_blocks.len();
84+
new_blocks.push(call_guard);
85+
*destination = BasicBlock::new(idx);
9186
}
87+
_ => {}
9288
}
9389
}
9490

@@ -99,15 +95,4 @@ impl<'tcx> MirPass<'tcx> for BreakCleanupEdges {
9995
}
10096
}
10197

102-
impl Pass for BreakCleanupEdges {}
103-
104-
// Returns true if the terminator is a call that would use an invoke in LLVM.
105-
fn term_is_invoke(term: &Terminator) -> bool {
106-
match term.kind {
107-
TerminatorKind::Call { cleanup: Some(_), .. } |
108-
// FIXME: not sure whether we need this one
109-
TerminatorKind::Drop { unwind: Some(_), .. } |
110-
TerminatorKind::DropAndReplace { .. } => true,
111-
_ => false
112-
}
113-
}
98+
impl Pass for AddCallGuards {}
+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright 2015 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+
//! This pass just dumps MIR at a specified point.
12+
13+
use rustc::ty::TyCtxt;
14+
use rustc::mir::repr::*;
15+
use rustc::mir::transform::{Pass, MirPass, MirSource};
16+
use pretty;
17+
18+
pub struct DumpMir<'a>(pub &'a str);
19+
20+
impl<'b, 'tcx> MirPass<'tcx> for DumpMir<'b> {
21+
fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
22+
src: MirSource, mir: &mut Mir<'tcx>) {
23+
pretty::dump_mir(tcx, self.0, &0, src, mir, None);
24+
}
25+
}
26+
27+
impl<'b> Pass for DumpMir<'b> {}

src/librustc_mir/transform/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub mod simplify_cfg;
1313
pub mod erase_regions;
1414
pub mod no_landing_pads;
1515
pub mod type_check;
16-
pub mod break_cleanup_edges;
16+
pub mod add_call_guards;
1717
pub mod promote_consts;
1818
pub mod qualify_consts;
19+
pub mod dump_mir;

0 commit comments

Comments
 (0)