integrate scopes into MIR
This commit is contained in:
parent
b76f818cad
commit
464c02e336
@ -32,6 +32,10 @@ pub struct Mir<'tcx> {
|
||||
/// that indexes into this vector.
|
||||
pub basic_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
|
||||
/// List of lexical scopes; these are referenced by statements and
|
||||
/// used (eventually) for debuginfo. Indexed by a `ScopeId`.
|
||||
pub scopes: ScopeDataVec,
|
||||
|
||||
/// Return type of the function.
|
||||
pub return_ty: FnOutput<'tcx>,
|
||||
|
||||
@ -613,13 +617,61 @@ impl<'tcx> Debug for Lvalue<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Scopes
|
||||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ScopeDataVec {
|
||||
pub vec: Vec<ScopeData>
|
||||
}
|
||||
|
||||
impl ScopeDataVec {
|
||||
pub fn new() -> Self {
|
||||
ScopeDataVec { vec: Vec::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ScopeId> for ScopeDataVec {
|
||||
type Output = ScopeData;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: ScopeId) -> &ScopeData {
|
||||
&self.vec[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<ScopeId> for ScopeDataVec {
|
||||
#[inline]
|
||||
fn index_mut(&mut self, index: ScopeId) -> &mut ScopeData {
|
||||
&mut self.vec[index.index()]
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ScopeId(u32);
|
||||
|
||||
impl ScopeId {
|
||||
pub fn new(index: usize) -> ScopeId {
|
||||
assert!(index < (u32::MAX as usize));
|
||||
ScopeId(index as u32)
|
||||
}
|
||||
|
||||
pub fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||
pub struct ScopeData {
|
||||
pub parent_scope: Option<ScopeId>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Operands
|
||||
//
|
||||
|
||||
/// These are values that can appear inside an rvalue (or an index
|
||||
/// lvalue). They are intentionally limited to prevent rvalues from
|
||||
/// being nested in one another.
|
||||
|
||||
#[derive(Clone, PartialEq, RustcEncodable, RustcDecodable)]
|
||||
pub enum Operand<'tcx> {
|
||||
Consume(Lvalue<'tcx>),
|
||||
|
@ -51,7 +51,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
}));
|
||||
}
|
||||
StmtKind::Let { remainder_scope, init_scope, pattern, initializer } => {
|
||||
this.push_scope(remainder_scope);
|
||||
this.push_scope(remainder_scope, block);
|
||||
let_extent_stack.push(remainder_scope);
|
||||
unpack!(block = this.in_scope(init_scope, block, move |this| {
|
||||
// FIXME #30046 ^~~~
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
//! Routines for manipulating the control-flow graph.
|
||||
|
||||
use build::CFG;
|
||||
use build::{CFG, Location};
|
||||
use rustc::mir::repr::*;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
@ -43,6 +43,11 @@ impl<'tcx> CFG<'tcx> {
|
||||
self.block_data_mut(block).statements.push(statement);
|
||||
}
|
||||
|
||||
pub fn current_location(&mut self, block: BasicBlock) -> Location {
|
||||
let index = self.block_data(block).statements.len();
|
||||
Location { block: block, statement_index: index }
|
||||
}
|
||||
|
||||
pub fn push_assign(&mut self,
|
||||
block: BasicBlock,
|
||||
span: Span,
|
||||
|
@ -21,8 +21,26 @@ use syntax::codemap::Span;
|
||||
pub struct Builder<'a, 'tcx: 'a> {
|
||||
hir: Cx<'a, 'tcx>,
|
||||
cfg: CFG<'tcx>,
|
||||
|
||||
// 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.
|
||||
scope_auxiliary: Vec<ScopeAuxiliary>,
|
||||
|
||||
// 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
|
||||
scope_data_vec: ScopeDataVec,
|
||||
|
||||
var_decls: Vec<VarDecl<'tcx>>,
|
||||
var_indices: FnvHashMap<ast::NodeId, u32>,
|
||||
temp_decls: Vec<TempDecl<'tcx>>,
|
||||
@ -33,6 +51,42 @@ struct CFG<'tcx> {
|
||||
basic_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
}
|
||||
|
||||
/// For each scope, we track the extent (from the HIR) and a
|
||||
/// single-entry-multiple-exit subgraph that contains all the
|
||||
/// statements/terminators within it.
|
||||
///
|
||||
/// This information is separated out from the main `ScopeData`
|
||||
/// because it is short-lived. First, the extent contains node-ids,
|
||||
/// so it cannot be saved and re-loaded. Second, any optimization will mess up
|
||||
/// the dominator/postdominator information.
|
||||
///
|
||||
/// The intention is basically to use this information to do
|
||||
/// regionck/borrowck and then throw it away once we are done.
|
||||
pub struct ScopeAuxiliary {
|
||||
/// extent of this scope from the MIR.
|
||||
pub extent: CodeExtent,
|
||||
|
||||
/// "entry point": dominator of all nodes in the scope
|
||||
pub dom: Location,
|
||||
|
||||
/// "exit points": mutual postdominators of all nodes in the scope
|
||||
pub postdoms: Vec<Location>,
|
||||
}
|
||||
|
||||
pub struct Location {
|
||||
/// the location is within this block
|
||||
pub block: BasicBlock,
|
||||
|
||||
/// the location is the start of the this statement; or, if `statement_index`
|
||||
/// == num-statements, then the start of the terminator.
|
||||
pub statement_index: usize,
|
||||
}
|
||||
|
||||
pub struct MirPlusPlus<'tcx> {
|
||||
pub mir: Mir<'tcx>,
|
||||
pub scope_auxiliary: Vec<ScopeAuxiliary>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
/// The `BlockAnd` "monad" packages up the new basic block along with a
|
||||
/// produced value (sometimes just unit, of course). The `unpack!`
|
||||
@ -86,13 +140,15 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||
argument_extent: CodeExtent,
|
||||
return_ty: FnOutput<'tcx>,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> Mir<'tcx> {
|
||||
-> MirPlusPlus<'tcx> {
|
||||
let cfg = CFG { basic_blocks: vec![] };
|
||||
|
||||
let mut builder = Builder {
|
||||
hir: hir,
|
||||
cfg: cfg,
|
||||
scopes: vec![],
|
||||
scope_data_vec: ScopeDataVec::new(),
|
||||
scope_auxiliary: vec![],
|
||||
loop_scopes: vec![],
|
||||
temp_decls: vec![],
|
||||
var_decls: vec![],
|
||||
@ -113,13 +169,17 @@ pub fn construct<'a,'tcx>(hir: Cx<'a,'tcx>,
|
||||
builder.cfg.terminate(block, Terminator::Goto { target: END_BLOCK });
|
||||
builder.cfg.terminate(END_BLOCK, Terminator::Return);
|
||||
|
||||
Mir {
|
||||
basic_blocks: builder.cfg.basic_blocks,
|
||||
var_decls: builder.var_decls,
|
||||
arg_decls: arg_decls,
|
||||
temp_decls: builder.temp_decls,
|
||||
return_ty: return_ty,
|
||||
span: span
|
||||
MirPlusPlus {
|
||||
mir: Mir {
|
||||
basic_blocks: builder.cfg.basic_blocks,
|
||||
scopes: builder.scope_data_vec,
|
||||
var_decls: builder.var_decls,
|
||||
arg_decls: arg_decls,
|
||||
temp_decls: builder.temp_decls,
|
||||
return_ty: return_ty,
|
||||
span: span
|
||||
},
|
||||
scope_auxiliary: builder.scope_auxiliary,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,7 +86,7 @@ should go to.
|
||||
|
||||
*/
|
||||
|
||||
use build::{BlockAnd, BlockAndExtension, Builder, CFG};
|
||||
use build::{BlockAnd, BlockAndExtension, Builder, CFG, ScopeAuxiliary};
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::lang_items;
|
||||
use rustc::middle::subst::{Substs, Subst, VecPerParamSpace};
|
||||
@ -98,8 +98,11 @@ use rustc::middle::const_eval::ConstVal;
|
||||
use rustc_const_eval::ConstInt;
|
||||
|
||||
pub struct Scope<'tcx> {
|
||||
// the scope-id within the scope_data_vec
|
||||
id: ScopeId,
|
||||
extent: CodeExtent,
|
||||
drops: Vec<DropData<'tcx>>,
|
||||
|
||||
// A scope may only have one associated free, because:
|
||||
// 1. We require a `free` to only be scheduled in the scope of `EXPR` in `box EXPR`;
|
||||
// 2. It only makes sense to have it translated into the diverge-path.
|
||||
@ -208,7 +211,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
where F: FnOnce(&mut Builder<'a, 'tcx>) -> BlockAnd<R>
|
||||
{
|
||||
debug!("in_scope(extent={:?}, block={:?})", extent, block);
|
||||
self.push_scope(extent);
|
||||
self.push_scope(extent, block);
|
||||
let rv = unpack!(block = f(self));
|
||||
unpack!(block = self.pop_scope(extent, block));
|
||||
debug!("in_scope: exiting extent={:?} block={:?}", extent, block);
|
||||
@ -219,26 +222,44 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// scope and call `pop_scope` afterwards. Note that these two
|
||||
/// calls must be paired; using `in_scope` as a convenience
|
||||
/// wrapper maybe preferable.
|
||||
pub fn push_scope(&mut self, extent: CodeExtent) {
|
||||
pub fn push_scope(&mut self, extent: CodeExtent, entry: BasicBlock) {
|
||||
debug!("push_scope({:?})", extent);
|
||||
let parent_id = self.scopes.last().map(|s| s.id);
|
||||
let id = ScopeId::new(self.scope_data_vec.vec.len());
|
||||
self.scope_data_vec.vec.push(ScopeData {
|
||||
parent_scope: parent_id,
|
||||
});
|
||||
self.scopes.push(Scope {
|
||||
extent: extent.clone(),
|
||||
id: id,
|
||||
extent: extent,
|
||||
drops: vec![],
|
||||
free: None
|
||||
});
|
||||
self.scope_auxiliary.push(ScopeAuxiliary {
|
||||
extent: extent,
|
||||
dom: self.cfg.current_location(entry),
|
||||
postdoms: vec![]
|
||||
});
|
||||
}
|
||||
|
||||
/// Pops a scope, which should have extent `extent`, adding any
|
||||
/// drops onto the end of `block` that are needed. This must
|
||||
/// match 1-to-1 with `push_scope`.
|
||||
pub fn pop_scope(&mut self, extent: CodeExtent, block: BasicBlock) -> BlockAnd<()> {
|
||||
pub fn pop_scope(&mut self,
|
||||
extent: CodeExtent,
|
||||
mut block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
debug!("pop_scope({:?}, {:?})", extent, block);
|
||||
// We need to have `cached_block`s available for all the drops, so we call diverge_cleanup
|
||||
// to make sure all the `cached_block`s are filled in.
|
||||
self.diverge_cleanup();
|
||||
let scope = self.scopes.pop().unwrap();
|
||||
assert_eq!(scope.extent, extent);
|
||||
build_scope_drops(&mut self.cfg, &scope, &self.scopes[..], block)
|
||||
unpack!(block = build_scope_drops(&mut self.cfg, &scope, &self.scopes, block));
|
||||
self.scope_auxiliary[scope.id.index()]
|
||||
.postdoms
|
||||
.push(self.cfg.current_location(block));
|
||||
block.and(())
|
||||
}
|
||||
|
||||
|
||||
@ -269,6 +290,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
self.cfg.terminate(block, free);
|
||||
block = next;
|
||||
}
|
||||
self.scope_auxiliary[scope.id.index()]
|
||||
.postdoms
|
||||
.push(self.cfg.current_location(block));
|
||||
}
|
||||
self.cfg.terminate(block, Terminator::Goto { target: target });
|
||||
}
|
||||
|
@ -19,7 +19,7 @@
|
||||
extern crate syntax;
|
||||
extern crate rustc_front;
|
||||
|
||||
use build;
|
||||
use build::{self, MirPlusPlus};
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::mir::repr::Mir;
|
||||
use hair::cx::Cx;
|
||||
@ -182,8 +182,14 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
|
||||
let parameter_scope =
|
||||
cx.tcx().region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
|
||||
let mut mir = build::construct(cx, span, implicit_arg_tys, arguments,
|
||||
parameter_scope, fn_sig.output, body);
|
||||
let MirPlusPlus { mut mir, scope_auxiliary: _ } =
|
||||
build::construct(cx,
|
||||
span,
|
||||
implicit_arg_tys,
|
||||
arguments,
|
||||
parameter_scope,
|
||||
fn_sig.output,
|
||||
body);
|
||||
|
||||
match cx.tcx().node_id_to_type(fn_id).sty {
|
||||
ty::TyFnDef(_, _, f) if f.abi == Abi::RustCall => {
|
||||
|
Loading…
Reference in New Issue
Block a user