MIR: Do not require END_BLOCK to always exist
Once upon a time, along with START_BLOCK and END_BLOCK in the castle of important blocks also lived a RESUME_BLOCK (or was it UNWIND_BLOCK? Either works, I don’t remember anymore). This trinity of important blocks were required to always exist from the birth to death of the MIR-land they belonged to. Some time later, it was discovered that RESUME_BLOCK was just a lazy goon enjoying comfortable life in the light of fame of the other two. Needless to say, once found out, the RESUME_BLOCK was quickly slain and disposed of. Now, the all-seeing eye of ours discovers that END_BLOCK is actually the more evil and better disguised twin of the slain RESUME_BLOCK. Thus END_BLOCK gets slain and quickly disposed of. Glory to the START_BLOCK, one and only lord of the important blocks’ castle! --- 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.
This commit is contained in:
parent
073a09fd63
commit
135657206f
6 changed files with 16 additions and 15 deletions
|
|
@ -59,9 +59,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())
|
||||
|
|
@ -216,6 +213,13 @@ impl BasicBlock {
|
|||
BasicBlock(index as u32)
|
||||
}
|
||||
|
||||
/// Returns a BasicBlock with index 1. This is actual end block (containing
|
||||
/// the Return terminator) only during the building of MIR and should not be
|
||||
/// used outside that.
|
||||
pub const fn end_block() -> BasicBlock {
|
||||
BasicBlock(1)
|
||||
}
|
||||
|
||||
/// Extract the index.
|
||||
pub fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
|
|
@ -305,8 +309,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
|
||||
|
|
|
|||
|
|
@ -262,7 +262,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
|||
}
|
||||
};
|
||||
let extent = this.extent_of_return_scope();
|
||||
this.exit_scope(expr_span, extent, block, END_BLOCK);
|
||||
this.exit_scope(expr_span, extent, block, BasicBlock::end_block());
|
||||
this.cfg.start_new_block().unit()
|
||||
}
|
||||
ExprKind::Call { ty, fun, args } => {
|
||||
|
|
|
|||
|
|
@ -183,7 +183,8 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||
};
|
||||
|
||||
assert_eq!(builder.cfg.start_new_block(), START_BLOCK);
|
||||
assert_eq!(builder.cfg.start_new_block(), END_BLOCK);
|
||||
let end_block = builder.cfg.start_new_block();
|
||||
assert_eq!(end_block, BasicBlock::end_block());
|
||||
|
||||
|
||||
let mut arg_decls = None; // assigned to `Some` in closures below
|
||||
|
|
@ -205,11 +206,10 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
|||
}));
|
||||
|
||||
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: end_block });
|
||||
builder.cfg.terminate(end_block, call_site_scope_id, span,
|
||||
TerminatorKind::Return);
|
||||
|
||||
END_BLOCK.unit()
|
||||
end_block.unit()
|
||||
});
|
||||
|
||||
assert!(
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
|||
#![unstable(feature = "rustc_private", issue = "27812")]
|
||||
|
||||
#![feature(box_patterns)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(rustc_private)]
|
||||
#![feature(staged_api)]
|
||||
#![feature(question_mark)]
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue