Skip to content

Commit 4e86dcd

Browse files
committed
Remove diverge terminator
Unreachable terminator can be contained all within the trans.
1 parent 5b34690 commit 4e86dcd

File tree

10 files changed

+40
-67
lines changed

10 files changed

+40
-67
lines changed

src/librustc/mir/repr.rs

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
5151
/// where execution ends, on normal return
5252
pub const END_BLOCK: BasicBlock = BasicBlock(1);
5353

54-
/// where execution ends, on panic
55-
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
56-
5754
impl<'tcx> Mir<'tcx> {
5855
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
5956
(0..self.basic_blocks.len())
@@ -194,7 +191,7 @@ impl Debug for BasicBlock {
194191
#[derive(Debug, RustcEncodable, RustcDecodable)]
195192
pub struct BasicBlockData<'tcx> {
196193
pub statements: Vec<Statement<'tcx>>,
197-
pub terminator: Terminator<'tcx>,
194+
pub terminator: Option<Terminator<'tcx>>,
198195
}
199196

200197
#[derive(RustcEncodable, RustcDecodable)]
@@ -237,14 +234,6 @@ pub enum Terminator<'tcx> {
237234
targets: Vec<BasicBlock>,
238235
},
239236

240-
/// Indicates that the last statement in the block panics, aborts,
241-
/// etc. No successors. This terminator appears on exactly one
242-
/// basic block which we create in advance. However, during
243-
/// construction, we use this value as a sentinel for "terminator
244-
/// not yet assigned", and assert at the end that only the
245-
/// well-known diverging block actually diverges.
246-
Diverge,
247-
248237
/// Indicates that the landing pad is finished and unwinding should
249238
/// continue. Emitted by build::scope::diverge_cleanup.
250239
Resume,
@@ -317,7 +306,6 @@ impl<'tcx> Terminator<'tcx> {
317306
If { targets: ref b, .. } => b.as_slice(),
318307
Switch { targets: ref b, .. } => b,
319308
SwitchInt { targets: ref b, .. } => b,
320-
Diverge => &[],
321309
Resume => &[],
322310
Return => &[],
323311
Call { targets: ref b, .. } => b.as_slice(),
@@ -336,7 +324,6 @@ impl<'tcx> Terminator<'tcx> {
336324
If { targets: ref mut b, .. } => b.as_mut_slice(),
337325
Switch { targets: ref mut b, .. } => b,
338326
SwitchInt { targets: ref mut b, .. } => b,
339-
Diverge => &mut [],
340327
Resume => &mut [],
341328
Return => &mut [],
342329
Call { targets: ref mut b, .. } => b.as_mut_slice(),
@@ -350,12 +337,24 @@ impl<'tcx> Terminator<'tcx> {
350337
}
351338

352339
impl<'tcx> BasicBlockData<'tcx> {
353-
pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
340+
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
354341
BasicBlockData {
355342
statements: vec![],
356343
terminator: terminator,
357344
}
358345
}
346+
347+
/// Accessor for terminator.
348+
///
349+
/// Terminator may not be None after construction of the basic block is complete. This accessor
350+
/// provides a convenience way to reach the terminator.
351+
pub fn terminator(&self) -> &Terminator<'tcx> {
352+
self.terminator.as_ref().expect("invalid terminator state")
353+
}
354+
355+
pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
356+
self.terminator.as_mut().expect("invalid terminator state")
357+
}
359358
}
360359

361360
impl<'tcx> Debug for Terminator<'tcx> {
@@ -396,7 +395,6 @@ impl<'tcx> Terminator<'tcx> {
396395
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
397396
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
398397
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
399-
Diverge => write!(fmt, "diverge"),
400398
Return => write!(fmt, "return"),
401399
Resume => write!(fmt, "resume"),
402400
Call { .. } => {
@@ -414,7 +412,7 @@ impl<'tcx> Terminator<'tcx> {
414412
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
415413
use self::Terminator::*;
416414
match *self {
417-
Diverge | Return | Resume => vec![],
415+
Return | Resume => vec![],
418416
Goto { .. } => vec!["".into_cow()],
419417
If { .. } => vec!["true".into_cow(), "false".into_cow()],
420418
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],

src/librustc/mir/visit.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ pub trait Visitor<'tcx> {
8484
for statement in &data.statements {
8585
self.visit_statement(block, statement);
8686
}
87-
self.visit_terminator(block, &data.terminator);
87+
data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
8888
}
8989

9090
fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) {
@@ -132,7 +132,6 @@ pub trait Visitor<'tcx> {
132132
}
133133
}
134134

135-
Terminator::Diverge |
136135
Terminator::Resume |
137136
Terminator::Return => {
138137
}
@@ -374,7 +373,7 @@ pub trait MutVisitor<'tcx> {
374373
for statement in &mut data.statements {
375374
self.visit_statement(block, statement);
376375
}
377-
self.visit_terminator(block, &mut data.terminator);
376+
data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
378377
}
379378

380379
fn super_statement(&mut self,
@@ -429,7 +428,6 @@ pub trait MutVisitor<'tcx> {
429428
}
430429
}
431430

432-
Terminator::Diverge |
433431
Terminator::Resume |
434432
Terminator::Return => {
435433
}

src/librustc_mir/build/cfg.rs

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl<'tcx> CFG<'tcx> {
2828

2929
pub fn start_new_block(&mut self) -> BasicBlock {
3030
let node_index = self.basic_blocks.len();
31-
self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge));
31+
self.basic_blocks.push(BasicBlockData::new(None));
3232
BasicBlock::new(node_index)
3333
}
3434

@@ -67,15 +67,9 @@ impl<'tcx> CFG<'tcx> {
6767
pub fn terminate(&mut self,
6868
block: BasicBlock,
6969
terminator: Terminator<'tcx>) {
70-
// Check whether this block has already been terminated. For
71-
// this, we rely on the fact that the initial state is to have
72-
// a Diverge terminator and an empty list of targets (which
73-
// is not a valid state).
74-
debug_assert!(match self.block_data(block).terminator { Terminator::Diverge => true,
75-
_ => false },
70+
debug_assert!(self.block_data(block).terminator.is_none(),
7671
"terminate: block {:?} already has a terminator set", block);
77-
78-
self.block_data_mut(block).terminator = terminator;
72+
self.block_data_mut(block).terminator = Some(terminator);
7973
}
8074
}
8175

src/librustc_mir/build/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
107107

108108
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
109109
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
110-
assert_eq!(builder.cfg.start_new_block(), DIVERGE_BLOCK);
111110

112111
let mut block = START_BLOCK;
113112
let arg_decls = unpack!(block = builder.args_and_body(block,

src/librustc_mir/graphviz.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
6262
// Terminator head at the bottom, not including the list of successor blocks. Those will be
6363
// displayed as labels on the edges between blocks.
6464
let mut terminator_head = String::new();
65-
data.terminator.fmt_head(&mut terminator_head).unwrap();
65+
data.terminator().fmt_head(&mut terminator_head).unwrap();
6666
try!(write!(w, r#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head)));
6767

6868
// Close the table, node label, and the node itself.
@@ -71,7 +71,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
7171

7272
/// Write graphviz DOT edges with labels between the given basic block and all of its successors.
7373
fn write_edges<W: Write>(source: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<()> {
74-
let terminator = &mir.basic_block_data(source).terminator;
74+
let terminator = &mir.basic_block_data(source).terminator();
7575
let labels = terminator.fmt_successor_labels();
7676

7777
for (&target, label) in terminator.successors().iter().zip(labels) {

src/librustc_mir/transform/erase_regions.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
5959
self.erase_regions_statement(statement);
6060
}
6161

62-
self.erase_regions_terminator(&mut basic_block.terminator);
62+
self.erase_regions_terminator(basic_block.terminator_mut());
6363
}
6464

6565
fn erase_regions_statement(&mut self,
@@ -79,7 +79,6 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
7979
terminator: &mut Terminator<'tcx>) {
8080
match *terminator {
8181
Terminator::Goto { .. } |
82-
Terminator::Diverge |
8382
Terminator::Resume |
8483
Terminator::Return => {
8584
/* nothing to do */

src/librustc_mir/transform/simplify_cfg.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010

1111
use rustc::middle::const_eval::ConstVal;
1212
use rustc::mir::repr::*;
13-
use std::mem;
1413
use transform::util;
1514
use transform::MirPass;
1615

@@ -27,11 +26,10 @@ impl SimplifyCfg {
2726
// These blocks are always required.
2827
seen[START_BLOCK.index()] = true;
2928
seen[END_BLOCK.index()] = true;
30-
seen[DIVERGE_BLOCK.index()] = true;
3129

3230
let mut worklist = vec![START_BLOCK];
3331
while let Some(bb) = worklist.pop() {
34-
for succ in mir.basic_block_data(bb).terminator.successors() {
32+
for succ in mir.basic_block_data(bb).terminator().successors() {
3533
if !seen[succ.index()] {
3634
seen[succ.index()] = true;
3735
worklist.push(*succ);
@@ -51,7 +49,7 @@ impl SimplifyCfg {
5149

5250
while mir.basic_block_data(target).statements.is_empty() {
5351
match mir.basic_block_data(target).terminator {
54-
Terminator::Goto { target: next } => {
52+
Some(Terminator::Goto { target: next }) => {
5553
if seen.contains(&next) {
5654
return None;
5755
}
@@ -67,9 +65,9 @@ impl SimplifyCfg {
6765

6866
let mut changed = false;
6967
for bb in mir.all_basic_blocks() {
70-
// Temporarily swap out the terminator we're modifying to keep borrowck happy
71-
let mut terminator = Terminator::Diverge;
72-
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
68+
// Temporarily take ownership of the terminator we're modifying to keep borrowck happy
69+
let mut terminator = mir.basic_block_data_mut(bb).terminator.take()
70+
.expect("invalid terminator state");
7371

7472
for target in terminator.successors_mut() {
7573
let new_target = match final_target(mir, *target) {
@@ -80,22 +78,19 @@ impl SimplifyCfg {
8078
changed |= *target != new_target;
8179
*target = new_target;
8280
}
83-
84-
mir.basic_block_data_mut(bb).terminator = terminator;
81+
mir.basic_block_data_mut(bb).terminator = Some(terminator);
8582
}
86-
8783
changed
8884
}
8985

9086
fn simplify_branches(&self, mir: &mut Mir) -> bool {
9187
let mut changed = false;
9288

9389
for bb in mir.all_basic_blocks() {
94-
// Temporarily swap out the terminator we're modifying to keep borrowck happy
95-
let mut terminator = Terminator::Diverge;
96-
mem::swap(&mut terminator, &mut mir.basic_block_data_mut(bb).terminator);
90+
let basic_block = mir.basic_block_data_mut(bb);
91+
let mut terminator = basic_block.terminator_mut();
9792

98-
mir.basic_block_data_mut(bb).terminator = match terminator {
93+
*terminator = match *terminator {
9994
Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
10095
changed = true;
10196
Terminator::Goto { target: targets.0 }
@@ -115,7 +110,7 @@ impl SimplifyCfg {
115110
Terminator::SwitchInt { ref targets, .. } if targets.len() == 1 => {
116111
Terminator::Goto { target: targets[0] }
117112
}
118-
_ => terminator
113+
_ => continue
119114
}
120115
}
121116

@@ -131,7 +126,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
131126
changed |= self.remove_goto_chains(mir);
132127
self.remove_dead_blocks(mir);
133128
}
134-
135129
// FIXME: Should probably be moved into some kind of pass manager
136130
mir.basic_blocks.shrink_to_fit();
137131
}

src/librustc_mir/transform/util.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use rustc::mir::repr::*;
1515
/// in a single pass
1616
pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
1717
for bb in mir.all_basic_blocks() {
18-
for target in mir.basic_block_data_mut(bb).terminator.successors_mut() {
18+
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
1919
*target = replacements[target.index()];
2020
}
2121
}

src/librustc_trans/trans/mir/block.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
3333
bcx = self.trans_statement(bcx, statement);
3434
}
3535

36-
debug!("trans_block: terminator: {:?}", data.terminator);
36+
debug!("trans_block: terminator: {:?}", data.terminator());
3737

38-
match data.terminator {
38+
match *data.terminator() {
3939
mir::Terminator::Goto { target } => {
4040
build::Br(bcx, self.llblock(target), DebugLoc::None)
4141
}
@@ -82,10 +82,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
8282
}
8383
}
8484

85-
mir::Terminator::Diverge => {
86-
build::Unreachable(bcx);
87-
}
88-
8985
mir::Terminator::Resume => {
9086
if let Some(llpersonalityslot) = self.llpersonalityslot {
9187
let lp = build::Load(bcx, llpersonalityslot);

src/librustc_trans/trans/mir/mod.rs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {
125125

126126
// Translate the body of each block
127127
for &bb in &mir_blocks {
128-
if bb != mir::DIVERGE_BLOCK {
129-
mircx.trans_block(bb);
130-
}
128+
// NB that we do not handle the Resume terminator specially, because a block containing
129+
// that terminator will have a higher block number than a function call which should take
130+
// care of filling in that information.
131+
mircx.trans_block(bb);
131132
}
132-
133-
// Total hack: translate DIVERGE_BLOCK last. This is so that any
134-
// panics which the fn may do can initialize the
135-
// `llpersonalityslot` cell. We don't do this up front because the
136-
// LLVM type of it is (frankly) annoying to compute.
137-
mircx.trans_block(mir::DIVERGE_BLOCK);
138133
}
139134

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

0 commit comments

Comments
 (0)