]> git.lizzy.rs Git - rust.git/commitdiff
integrate scopes into MIR
authorNiko Matsakis <niko@alum.mit.edu>
Wed, 9 Mar 2016 16:04:26 +0000 (11:04 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Wed, 23 Mar 2016 20:37:48 +0000 (16:37 -0400)
src/librustc/mir/repr.rs
src/librustc_mir/build/block.rs
src/librustc_mir/build/cfg.rs
src/librustc_mir/build/mod.rs
src/librustc_mir/build/scope.rs
src/librustc_mir/mir_map.rs

index ff3e292f45818c4245982fc941740a89842ee107..6723fc72a40eb2189f6d2b1fc446c10292c56db7 100644 (file)
@@ -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 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
     }
 }
 
+///////////////////////////////////////////////////////////////////////////
+// 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>),
index 4c80eab102fc5f2ff826d3bf00d6c5660b95080b..ca23be7dc06185402caeae8cdc70a7b89a28045e 100644 (file)
@@ -51,7 +51,7 @@ pub fn ast_block(&mut self,
                         }));
                     }
                     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                              ^~~~
index c7147d111aace02a0dddeb90e6e8107a629f700c..d804fc8635a92526765802e870fef0f579e7ad6a 100644 (file)
@@ -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 @@ pub fn push(&mut self, block: BasicBlock, statement: Statement<'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,
index b40775f939f75a3abb3be55db739b4e1619ab7c4..41259f8a281dead5be4ed97e1577720a11cd57e5 100644 (file)
 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,
     }
 }
 
index 6d411b9c07b311dc5394b1bc2cc0c4b946d53f8c..6a734e1816a25dc3f296a364c1df17b8ea2793fa 100644 (file)
@@ -86,7 +86,7 @@
 
 */
 
-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.
@@ -208,7 +211,7 @@ pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F
         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 @@ pub fn in_scope<F, R>(&mut self, extent: CodeExtent, mut block: BasicBlock, f: F
     /// 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 @@ pub fn exit_scope(&mut self,
                 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 });
     }
index 05dbd63ef1a4221b827ba4486878e614ae5c5f36..71037d1f080700b6d6311eb9e91e8fa638daad1b 100644 (file)
@@ -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 => {