Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Remove diverge terminator
Unreachable terminator can be contained all within the trans.
  • Loading branch information
nagisa committed Jan 6, 2016
commit 4e86dcdb7295e88d3ccc28b508ba69a24fefa371
32 changes: 15 additions & 17 deletions src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,6 @@ pub const START_BLOCK: BasicBlock = BasicBlock(0);
/// where execution ends, on normal return
pub const END_BLOCK: BasicBlock = BasicBlock(1);

/// where execution ends, on panic
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);

impl<'tcx> Mir<'tcx> {
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
(0..self.basic_blocks.len())
Expand Down Expand Up @@ -194,7 +191,7 @@ impl Debug for BasicBlock {
#[derive(Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
pub statements: Vec<Statement<'tcx>>,
pub terminator: Terminator<'tcx>,
pub terminator: Option<Terminator<'tcx>>,
}

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

/// Indicates that the last statement in the block panics, aborts,
/// etc. No successors. This terminator appears on exactly one
/// basic block which we create in advance. However, during
/// construction, we use this value as a sentinel for "terminator
/// not yet assigned", and assert at the end that only the
/// well-known diverging block actually diverges.
Diverge,

/// Indicates that the landing pad is finished and unwinding should
/// continue. Emitted by build::scope::diverge_cleanup.
Resume,
Expand Down Expand Up @@ -317,7 +306,6 @@ impl<'tcx> Terminator<'tcx> {
If { targets: ref b, .. } => b.as_slice(),
Switch { targets: ref b, .. } => b,
SwitchInt { targets: ref b, .. } => b,
Diverge => &[],
Resume => &[],
Return => &[],
Call { targets: ref b, .. } => b.as_slice(),
Expand All @@ -336,7 +324,6 @@ impl<'tcx> Terminator<'tcx> {
If { targets: ref mut b, .. } => b.as_mut_slice(),
Switch { targets: ref mut b, .. } => b,
SwitchInt { targets: ref mut b, .. } => b,
Diverge => &mut [],
Resume => &mut [],
Return => &mut [],
Call { targets: ref mut b, .. } => b.as_mut_slice(),
Expand All @@ -350,12 +337,24 @@ impl<'tcx> Terminator<'tcx> {
}

impl<'tcx> BasicBlockData<'tcx> {
pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
pub fn new(terminator: Option<Terminator<'tcx>>) -> BasicBlockData<'tcx> {
BasicBlockData {
statements: vec![],
terminator: terminator,
}
}

/// Accessor for terminator.
///
/// Terminator may not be None after construction of the basic block is complete. This accessor
/// provides a convenience way to reach the terminator.
pub fn terminator(&self) -> &Terminator<'tcx> {
self.terminator.as_ref().expect("invalid terminator state")
}

pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> {
self.terminator.as_mut().expect("invalid terminator state")
}
}

impl<'tcx> Debug for Terminator<'tcx> {
Expand Down Expand Up @@ -396,7 +395,6 @@ impl<'tcx> Terminator<'tcx> {
If { cond: ref lv, .. } => write!(fmt, "if({:?})", lv),
Switch { discr: ref lv, .. } => write!(fmt, "switch({:?})", lv),
SwitchInt { discr: ref lv, .. } => write!(fmt, "switchInt({:?})", lv),
Diverge => write!(fmt, "diverge"),
Return => write!(fmt, "return"),
Resume => write!(fmt, "resume"),
Call { .. } => {
Expand All @@ -414,7 +412,7 @@ impl<'tcx> Terminator<'tcx> {
pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
use self::Terminator::*;
match *self {
Diverge | Return | Resume => vec![],
Return | Resume => vec![],
Goto { .. } => vec!["".into_cow()],
If { .. } => vec!["true".into_cow(), "false".into_cow()],
Call { .. } => vec!["return".into_cow(), "unwind".into_cow()],
Expand Down
6 changes: 2 additions & 4 deletions src/librustc/mir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub trait Visitor<'tcx> {
for statement in &data.statements {
self.visit_statement(block, statement);
}
self.visit_terminator(block, &data.terminator);
data.terminator.as_ref().map(|r| self.visit_terminator(block, r));
}

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

Terminator::Diverge |
Terminator::Resume |
Terminator::Return => {
}
Expand Down Expand Up @@ -374,7 +373,7 @@ pub trait MutVisitor<'tcx> {
for statement in &mut data.statements {
self.visit_statement(block, statement);
}
self.visit_terminator(block, &mut data.terminator);
data.terminator.as_mut().map(|r| self.visit_terminator(block, r));
}

fn super_statement(&mut self,
Expand Down Expand Up @@ -429,7 +428,6 @@ pub trait MutVisitor<'tcx> {
}
}

Terminator::Diverge |
Terminator::Resume |
Terminator::Return => {
}
Expand Down
12 changes: 3 additions & 9 deletions src/librustc_mir/build/cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ impl<'tcx> CFG<'tcx> {

pub fn start_new_block(&mut self) -> BasicBlock {
let node_index = self.basic_blocks.len();
self.basic_blocks.push(BasicBlockData::new(Terminator::Diverge));
self.basic_blocks.push(BasicBlockData::new(None));
BasicBlock::new(node_index)
}

Expand Down Expand Up @@ -67,15 +67,9 @@ impl<'tcx> CFG<'tcx> {
pub fn terminate(&mut self,
block: BasicBlock,
terminator: Terminator<'tcx>) {
// Check whether this block has already been terminated. For
// this, we rely on the fact that the initial state is to have
// a Diverge terminator and an empty list of targets (which
// is not a valid state).
debug_assert!(match self.block_data(block).terminator { Terminator::Diverge => true,
_ => false },
debug_assert!(self.block_data(block).terminator.is_none(),
"terminate: block {:?} already has a terminator set", block);

self.block_data_mut(block).terminator = terminator;
self.block_data_mut(block).terminator = Some(terminator);
}
}

1 change: 0 additions & 1 deletion src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,

assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
assert_eq!(builder.cfg.start_new_block(), DIVERGE_BLOCK);

let mut block = START_BLOCK;
let arg_decls = unpack!(block = builder.args_and_body(block,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_mir/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ fn write_node<W: Write>(block: BasicBlock, mir: &Mir, w: &mut W) -> io::Result<(
// Terminator head at the bottom, not including the list of successor blocks. Those will be
// displayed as labels on the edges between blocks.
let mut terminator_head = String::new();
data.terminator.fmt_head(&mut terminator_head).unwrap();
data.terminator().fmt_head(&mut terminator_head).unwrap();
try!(write!(w, r#"<tr><td align="left">{}</td></tr>"#, dot::escape_html(&terminator_head)));

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

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

for (&target, label) in terminator.successors().iter().zip(labels) {
Expand Down
3 changes: 1 addition & 2 deletions src/librustc_mir/transform/erase_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
self.erase_regions_statement(statement);
}

self.erase_regions_terminator(&mut basic_block.terminator);
self.erase_regions_terminator(basic_block.terminator_mut());
}

fn erase_regions_statement(&mut self,
Expand All @@ -79,7 +79,6 @@ impl<'a, 'tcx> EraseRegions<'a, 'tcx> {
terminator: &mut Terminator<'tcx>) {
match *terminator {
Terminator::Goto { .. } |
Terminator::Diverge |
Terminator::Resume |
Terminator::Return => {
/* nothing to do */
Expand Down
26 changes: 10 additions & 16 deletions src/librustc_mir/transform/simplify_cfg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

use rustc::middle::const_eval::ConstVal;
use rustc::mir::repr::*;
use std::mem;
use transform::util;
use transform::MirPass;

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

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

while mir.basic_block_data(target).statements.is_empty() {
match mir.basic_block_data(target).terminator {
Terminator::Goto { target: next } => {
Some(Terminator::Goto { target: next }) => {
if seen.contains(&next) {
return None;
}
Expand All @@ -67,9 +65,9 @@ impl SimplifyCfg {

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

for target in terminator.successors_mut() {
let new_target = match final_target(mir, *target) {
Expand All @@ -80,22 +78,19 @@ impl SimplifyCfg {
changed |= *target != new_target;
*target = new_target;
}

mir.basic_block_data_mut(bb).terminator = terminator;
mir.basic_block_data_mut(bb).terminator = Some(terminator);
}

changed
}

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

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

mir.basic_block_data_mut(bb).terminator = match terminator {
*terminator = match *terminator {
Terminator::If { ref targets, .. } if targets.0 == targets.1 => {
changed = true;
Terminator::Goto { target: targets.0 }
Expand All @@ -115,7 +110,7 @@ impl SimplifyCfg {
Terminator::SwitchInt { ref targets, .. } if targets.len() == 1 => {
Terminator::Goto { target: targets[0] }
}
_ => terminator
_ => continue
}
}

Expand All @@ -131,7 +126,6 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg {
changed |= self.remove_goto_chains(mir);
self.remove_dead_blocks(mir);
}

// FIXME: Should probably be moved into some kind of pass manager
mir.basic_blocks.shrink_to_fit();
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use rustc::mir::repr::*;
/// in a single pass
pub fn update_basic_block_ids(mir: &mut Mir, replacements: &[BasicBlock]) {
for bb in mir.all_basic_blocks() {
for target in mir.basic_block_data_mut(bb).terminator.successors_mut() {
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
*target = replacements[target.index()];
}
}
Expand Down
8 changes: 2 additions & 6 deletions src/librustc_trans/trans/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
bcx = self.trans_statement(bcx, statement);
}

debug!("trans_block: terminator: {:?}", data.terminator);
debug!("trans_block: terminator: {:?}", data.terminator());

match data.terminator {
match *data.terminator() {
mir::Terminator::Goto { target } => {
build::Br(bcx, self.llblock(target), DebugLoc::None)
}
Expand Down Expand Up @@ -82,10 +82,6 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> {
}
}

mir::Terminator::Diverge => {
build::Unreachable(bcx);
}

mir::Terminator::Resume => {
if let Some(llpersonalityslot) = self.llpersonalityslot {
let lp = build::Load(bcx, llpersonalityslot);
Expand Down
13 changes: 4 additions & 9 deletions src/librustc_trans/trans/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,11 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) {

// Translate the body of each block
for &bb in &mir_blocks {
if bb != mir::DIVERGE_BLOCK {
mircx.trans_block(bb);
}
// NB that we do not handle the Resume terminator specially, because a block containing
// that terminator will have a higher block number than a function call which should take
// care of filling in that information.
mircx.trans_block(bb);
}

// Total hack: translate DIVERGE_BLOCK last. This is so that any
// panics which the fn may do can initialize the
// `llpersonalityslot` cell. We don't do this up front because the
// LLVM type of it is (frankly) annoying to compute.
mircx.trans_block(mir::DIVERGE_BLOCK);
}

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