]> git.lizzy.rs Git - rust.git/commitdiff
Remove diverge terminator
authorSimonas Kazlauskas <git@kazlauskas.me>
Fri, 18 Dec 2015 22:44:32 +0000 (00:44 +0200)
committerSimonas Kazlauskas <git@kazlauskas.me>
Wed, 6 Jan 2016 11:57:51 +0000 (13:57 +0200)
Unreachable terminator can be contained all within the trans.

src/librustc/mir/repr.rs
src/librustc/mir/visit.rs
src/librustc_mir/build/cfg.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/graphviz.rs
src/librustc_mir/transform/erase_regions.rs
src/librustc_mir/transform/simplify_cfg.rs
src/librustc_mir/transform/util.rs
src/librustc_trans/trans/mir/block.rs
src/librustc_trans/trans/mir/mod.rs

index 8a43b8d0aaf169662d965b78d6b72f6a4115710e..2878b3d5e4e9af1da1447d2c2488384a1643fb14 100644 (file)
@@ -51,9 +51,6 @@ pub struct Mir<'tcx> {
 /// 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())
@@ -194,7 +191,7 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
 #[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)]
@@ -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,
@@ -317,7 +306,6 @@ pub fn successors(&self) -> &[BasicBlock] {
             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(),
@@ -336,7 +324,6 @@ pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
             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(),
@@ -350,12 +337,24 @@ pub fn successors_mut(&mut self) -> &mut [BasicBlock] {
 }
 
 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> {
@@ -396,7 +395,6 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
             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 { .. } => {
@@ -414,7 +412,7 @@ pub fn fmt_head<W: Write>(&self, fmt: &mut W) -> fmt::Result {
     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()],
index 4d29a71c6e74853b7866d0e37e179f003d2986d8..52bb9aa3d5c5a8d43d1e0d6fbd577968869dd14b 100644 (file)
@@ -84,7 +84,7 @@ fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'t
         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>) {
@@ -132,7 +132,6 @@ fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>)
                 }
             }
 
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
             }
@@ -374,7 +373,7 @@ fn super_basic_block_data(&mut self,
         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,
@@ -429,7 +428,6 @@ fn super_terminator(&mut self,
                 }
             }
 
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
             }
index d28724c30aaa0b79730f8dbc7ef375bb11cc3760..2e70e6bb5ae0499e1a56eada967ae9258114459f 100644 (file)
@@ -28,7 +28,7 @@ pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'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)
     }
 
@@ -67,15 +67,9 @@ pub fn push_assign(&mut self,
     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);
     }
 }
 
index 8347a03cda6f72318b879e8daae6dab3c2567c0c..e6e5b8380b24121a05d062ad3625ab4df0c2d02e 100644 (file)
@@ -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,
index d1d3e80e3402f38df9ca0beedb636243277315d4..1b8fe6505583c43664cc0f7ea3c9c5bdf9a697df 100644 (file)
@@ -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.
@@ -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) {
index 90bb73dbe28d38a2bfc70f983ed107ea2bc2e69e..01d873abc6f92b77718f4189df7a3a7d2afdc216 100644 (file)
@@ -59,7 +59,7 @@ fn erase_regions_basic_block(&mut self,
             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,
@@ -79,7 +79,6 @@ fn erase_regions_terminator(&mut self,
                                 terminator: &mut Terminator<'tcx>) {
         match *terminator {
             Terminator::Goto { .. } |
-            Terminator::Diverge |
             Terminator::Resume |
             Terminator::Return => {
                 /* nothing to do */
index d0c0afc80a657dce2b7c166c4536cbdc1896a3cd..7a5a00a8d560b6e83cde98c3418e7094c72730c6 100644 (file)
@@ -10,7 +10,6 @@
 
 use rustc::middle::const_eval::ConstVal;
 use rustc::mir::repr::*;
-use std::mem;
 use transform::util;
 use transform::MirPass;
 
@@ -27,11 +26,10 @@ fn remove_dead_blocks(&self, mir: &mut Mir) {
         // 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);
@@ -51,7 +49,7 @@ fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
 
             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;
                         }
@@ -67,9 +65,9 @@ fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
 
         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) {
@@ -80,10 +78,8 @@ fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
                 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
     }
 
@@ -91,11 +87,10 @@ 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 }
@@ -115,7 +110,7 @@ fn simplify_branches(&self, mir: &mut Mir) -> bool {
                 Terminator::SwitchInt { ref targets, .. }  if targets.len() == 1 => {
                     Terminator::Goto { target: targets[0] }
                 }
-                _ => terminator
+                _ => continue
             }
         }
 
@@ -131,7 +126,6 @@ fn run_on_mir(&mut self, mir: &mut Mir<'tcx>) {
             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();
     }
index 951026945448527b40afda2e515e95e6e4524cca..7e44beb18a2e96c8029a5bf61974308ba0fa383f 100644 (file)
@@ -15,7 +15,7 @@
 /// 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()];
         }
     }
index 4c2bec14e5e25094099002558473c4b0dc28e540..c2645d9882b42160828af622d1a2b740788ba6d5 100644 (file)
@@ -33,9 +33,9 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
             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)
             }
@@ -82,10 +82,6 @@ pub fn trans_block(&mut self, bb: mir::BasicBlock) {
                 }
             }
 
-            mir::Terminator::Diverge => {
-                build::Unreachable(bcx);
-            }
-
             mir::Terminator::Resume => {
                 if let Some(llpersonalityslot) = self.llpersonalityslot {
                     let lp = build::Load(bcx, llpersonalityslot);
index 0ed76ebeb4362aabde20923530a8111e42260ae6..5403b53596c489d99b007514d3d647b9f9dde893 100644 (file)
@@ -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