diff options
| author | bors <bors@rust-lang.org> | 2016-04-20 21:25:26 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2016-04-20 21:25:26 -0700 |
| commit | 6e036082091bc253debeb22606a661af211610ff (patch) | |
| tree | 81ecef8d15aa1b65669915b82d65b14f80cff4d7 | |
| parent | 95545e7adcf1715eff2a31a53fe25ce2b012e62b (diff) | |
| parent | d1180afbd99d533802f57f8c1fbf8c2723831ef2 (diff) | |
| download | rust-6e036082091bc253debeb22606a661af211610ff.tar.gz rust-6e036082091bc253debeb22606a661af211610ff.zip | |
Auto merge of #33030 - nagisa:mir-unrequire-end-block, r=nikomatsakis
MIR: Do not require END_BLOCK to always exist Basically, all this does, is removing restriction for END_BLOCK to exist past the first invocation of RemoveDeadBlocks pass. This way for functions whose CFG does not reach the `END_BLOCK` end up not containing the block. As far as the implementation goes, I’m not entirely satisfied with the `BasicBlock::end_block`. I had hoped to make `new` a `const fn` and then just have a `const END_BLOCK` private to mir::build, but it turns out that constant functions don’t yet support conditionals nor a way to assert.
| -rw-r--r-- | src/librustc/mir/repr.rs | 6 | ||||
| -rw-r--r-- | src/librustc_mir/build/expr/into.rs | 3 | ||||
| -rw-r--r-- | src/librustc_mir/build/mod.rs | 50 | ||||
| -rw-r--r-- | src/librustc_mir/transform/remove_dead_blocks.rs | 3 | ||||
| -rw-r--r-- | src/librustc_trans/mir/mod.rs | 2 |
5 files changed, 35 insertions, 29 deletions
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 3bc65124d34..09383e69553 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -63,9 +63,6 @@ pub struct Mir<'tcx> { /// where execution begins pub const START_BLOCK: BasicBlock = BasicBlock(0); -/// where execution ends, on normal return -pub const END_BLOCK: BasicBlock = BasicBlock(1); - impl<'tcx> Mir<'tcx> { pub fn all_basic_blocks(&self) -> Vec<BasicBlock> { (0..self.basic_blocks.len()) @@ -322,8 +319,7 @@ pub enum TerminatorKind<'tcx> { Resume, /// Indicates a normal return. The ReturnPointer lvalue should - /// have been filled in by now. This should only occur in the - /// `END_BLOCK`. + /// have been filled in by now. This should occur at most once. Return, /// Drop the Lvalue diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index 231d7da10a0..fe32f1de0c5 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -262,7 +262,8 @@ impl<'a,'tcx> Builder<'a,'tcx> { } }; let extent = this.extent_of_return_scope(); - this.exit_scope(expr_span, extent, block, END_BLOCK); + let return_block = this.return_block(); + this.exit_scope(expr_span, extent, block, return_block); this.cfg.start_new_block().unit() } ExprKind::Call { ty, fun, args } => { diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 5284a2ef395..b1f35541134 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -26,23 +26,23 @@ pub struct Builder<'a, 'tcx: 'a> { fn_span: Span, - // the current set of scopes, updated as we traverse; - // see the `scope` module for more details + /// the current set of scopes, updated as we traverse; + /// see the `scope` module for more details scopes: Vec<scope::Scope<'tcx>>, - // for each scope, a span of blocks that defines it; - // we track these for use in region and borrow checking, - // but these are liable to get out of date once optimization - // begins. They are also hopefully temporary, and will be - // no longer needed when we adopt graph-based regions. + /// for each scope, a span of blocks that defines it; + /// we track these for use in region and borrow checking, + /// but these are liable to get out of date once optimization + /// begins. They are also hopefully temporary, and will be + /// no longer needed when we adopt graph-based regions. scope_auxiliary: ScopeAuxiliaryVec, - // the current set of loops; see the `scope` module for more - // details + /// the current set of loops; see the `scope` module for more + /// details loop_scopes: Vec<scope::LoopScope>, - // the vector of all scopes that we have created thus far; - // we track this for debuginfo later + /// the vector of all scopes that we have created thus far; + /// we track this for debuginfo later scope_datas: Vec<ScopeData>, var_decls: Vec<VarDecl<'tcx>>, @@ -50,9 +50,11 @@ pub struct Builder<'a, 'tcx: 'a> { temp_decls: Vec<TempDecl<'tcx>>, unit_temp: Option<Lvalue<'tcx>>, - // cached block with a RESUME terminator; we create this at the - // first panic + /// cached block with the RESUME terminator; this is created + /// when first set of cleanups are built. cached_resume_block: Option<BasicBlock>, + /// cached block with the RETURN terminator + cached_return_block: Option<BasicBlock>, } struct CFG<'tcx> { @@ -182,11 +184,10 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, var_indices: FnvHashMap(), unit_temp: None, cached_resume_block: None, + cached_return_block: None }; assert_eq!(builder.cfg.start_new_block(), START_BLOCK); - assert_eq!(builder.cfg.start_new_block(), END_BLOCK); - let mut arg_decls = None; // assigned to `Some` in closures below let call_site_extent = @@ -206,12 +207,12 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>, block.unit() })); + let return_block = builder.return_block(); builder.cfg.terminate(block, call_site_scope_id, span, - TerminatorKind::Goto { target: END_BLOCK }); - builder.cfg.terminate(END_BLOCK, call_site_scope_id, span, + TerminatorKind::Goto { target: return_block }); + builder.cfg.terminate(return_block, call_site_scope_id, span, TerminatorKind::Return); - - END_BLOCK.unit() + return_block.unit() }); assert!( @@ -329,6 +330,17 @@ impl<'a,'tcx> Builder<'a,'tcx> { } } } + + fn return_block(&mut self) -> BasicBlock { + match self.cached_return_block { + Some(rb) => rb, + None => { + let rb = self.cfg.start_new_block(); + self.cached_return_block = Some(rb); + rb + } + } + } } /////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_mir/transform/remove_dead_blocks.rs b/src/librustc_mir/transform/remove_dead_blocks.rs index dc1ddad124f..2099e9a435a 100644 --- a/src/librustc_mir/transform/remove_dead_blocks.rs +++ b/src/librustc_mir/transform/remove_dead_blocks.rs @@ -43,9 +43,8 @@ pub struct RemoveDeadBlocks; impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks { fn run_pass(&mut self, _: &TyCtxt<'tcx>, _: NodeId, mir: &mut Mir<'tcx>) { let mut seen = BitVector::new(mir.basic_blocks.len()); - // These blocks are always required. + // This block is always required. seen.insert(START_BLOCK.index()); - seen.insert(END_BLOCK.index()); let mut worklist = Vec::with_capacity(4); worklist.push(START_BLOCK); diff --git a/src/librustc_trans/mir/mod.rs b/src/librustc_trans/mir/mod.rs index 3edbea88c05..3874ebc9130 100644 --- a/src/librustc_trans/mir/mod.rs +++ b/src/librustc_trans/mir/mod.rs @@ -164,8 +164,6 @@ pub fn trans_mir<'blk, 'tcx: 'blk>(fcx: &'blk FunctionContext<'blk, 'tcx>) { .map(|&bb|{ if bb == mir::START_BLOCK { fcx.new_block("start", None) - } else if bb == mir::END_BLOCK { - fcx.new_block("end", None) } else { fcx.new_block(&format!("{:?}", bb), None) } |
