/// 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>,
}
}
+///////////////////////////////////////////////////////////////////////////
+// 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>),
}));
}
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 ^~~~
//! Routines for manipulating the control-flow graph.
-use build::CFG;
+use build::{CFG, Location};
use rustc::mir::repr::*;
use syntax::codemap::Span;
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,
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>>,
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!`
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![],
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,
}
}
*/
-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};
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.
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);
/// 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(())
}
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 });
}
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;
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 => {