about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/lib.rs1
-rw-r--r--src/librustc/mir/cache.rs69
-rw-r--r--src/librustc/mir/repr.rs20
-rw-r--r--src/librustc_mir/transform/add_call_guards.rs13
-rw-r--r--src/librustc_mir/transform/simplify_cfg.rs11
5 files changed, 93 insertions, 21 deletions
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 301c6e3dd1c..bc24b54a5c7 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -102,6 +102,7 @@ pub mod middle {
 }
 
 pub mod mir {
+    mod cache;
     pub mod repr;
     pub mod tcx;
     pub mod visit;
diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs
new file mode 100644
index 00000000000..138fed2d64e
--- /dev/null
+++ b/src/librustc/mir/cache.rs
@@ -0,0 +1,69 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::cell::{Ref, RefCell};
+use rustc_data_structures::indexed_vec::IndexVec;
+
+use mir::repr::{Mir, BasicBlock};
+
+use rustc_serialize as serialize;
+
+#[derive(Clone)]
+pub struct Cache {
+    predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
+}
+
+
+impl serialize::Encodable for Cache {
+    fn encode<S: serialize::Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
+        serialize::Encodable::encode(&(), s)
+    }
+}
+
+impl serialize::Decodable for Cache {
+    fn decode<D: serialize::Decoder>(d: &mut D) -> Result<Self, D::Error> {
+        serialize::Decodable::decode(d).map(|_v: ()| Self::new())
+    }
+}
+
+
+impl Cache {
+    pub fn new() -> Self {
+        Cache {
+            predecessors: RefCell::new(None)
+        }
+    }
+
+    pub fn invalidate(&self) {
+        // FIXME: consider being more fine-grained
+        *self.predecessors.borrow_mut() = None;
+    }
+
+    pub fn predecessors(&self, mir: &Mir) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+        if self.predecessors.borrow().is_none() {
+            *self.predecessors.borrow_mut() = Some(calculate_predecessors(mir));
+        }
+
+        Ref::map(self.predecessors.borrow(), |p| p.as_ref().unwrap())
+    }
+}
+
+fn calculate_predecessors(mir: &Mir) -> IndexVec<BasicBlock, Vec<BasicBlock>> {
+    let mut result = IndexVec::from_elem(vec![], mir.basic_blocks());
+    for (bb, data) in mir.basic_blocks().iter_enumerated() {
+        if let Some(ref term) = data.terminator {
+            for &tgt in term.successors().iter() {
+                result[tgt].push(bb);
+            }
+        }
+    }
+
+    result
+}
diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs
index 7394d0081ed..dad330aa59e 100644
--- a/src/librustc/mir/repr.rs
+++ b/src/librustc/mir/repr.rs
@@ -20,12 +20,15 @@ use rustc_back::slice;
 use hir::InlineAsm;
 use std::ascii;
 use std::borrow::{Cow};
+use std::cell::Ref;
 use std::fmt::{self, Debug, Formatter, Write};
 use std::{iter, u32};
 use std::ops::{Index, IndexMut};
 use syntax::ast::{self, Name};
 use syntax::codemap::Span;
 
+use super::cache::Cache;
+
 macro_rules! newtype_index {
     ($name:ident, $debug_name:expr) => (
         #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord,
@@ -88,6 +91,9 @@ pub struct Mir<'tcx> {
 
     /// A span representing this MIR, for error reporting
     pub span: Span,
+
+    /// A cache for various calculations
+    cache: Cache
 }
 
 /// where execution begins
@@ -113,7 +119,8 @@ impl<'tcx> Mir<'tcx> {
             arg_decls: arg_decls,
             temp_decls: temp_decls,
             upvar_decls: upvar_decls,
-            span: span
+            span: span,
+            cache: Cache::new()
         }
     }
 
@@ -124,8 +131,19 @@ impl<'tcx> Mir<'tcx> {
 
     #[inline]
     pub fn basic_blocks_mut(&mut self) -> &mut IndexVec<BasicBlock, BasicBlockData<'tcx>> {
+        self.cache.invalidate();
         &mut self.basic_blocks
     }
+
+    #[inline]
+    pub fn predecessors(&self) -> Ref<IndexVec<BasicBlock, Vec<BasicBlock>>> {
+        self.cache.predecessors(self)
+    }
+
+    #[inline]
+    pub fn predecessors_for(&self, bb: BasicBlock) -> Ref<Vec<BasicBlock>> {
+        Ref::map(self.predecessors(), |p| &p[bb])
+    }
 }
 
 impl<'tcx> Index<BasicBlock> for Mir<'tcx> {
diff --git a/src/librustc_mir/transform/add_call_guards.rs b/src/librustc_mir/transform/add_call_guards.rs
index dee9227fd9b..63e975128c7 100644
--- a/src/librustc_mir/transform/add_call_guards.rs
+++ b/src/librustc_mir/transform/add_call_guards.rs
@@ -11,7 +11,6 @@
 use rustc::ty::TyCtxt;
 use rustc::mir::repr::*;
 use rustc::mir::transform::{MirPass, MirSource, Pass};
-use rustc::mir::traversal;
 use rustc_data_structures::indexed_vec::{Idx, IndexVec};
 
 use pretty;
@@ -40,16 +39,8 @@ pub struct AddCallGuards;
 
 impl<'tcx> MirPass<'tcx> for AddCallGuards {
     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>, src: MirSource, mir: &mut Mir<'tcx>) {
-        let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks());
-
-        // Build the precedecessor map for the MIR
-        for (_, data) in traversal::preorder(mir) {
-            if let Some(ref term) = data.terminator {
-                for &tgt in term.successors().iter() {
-                    pred_count[tgt] += 1;
-                }
-            }
-        }
+        let pred_count: IndexVec<_, _> =
+            mir.predecessors().iter().map(|ps| ps.len()).collect();
 
         // We need a place to store the new blocks generated
         let mut new_blocks = Vec::new();
diff --git a/src/librustc_mir/transform/simplify_cfg.rs b/src/librustc_mir/transform/simplify_cfg.rs
index fcc82249953..9cee6b11c07 100644
--- a/src/librustc_mir/transform/simplify_cfg.rs
+++ b/src/librustc_mir/transform/simplify_cfg.rs
@@ -67,15 +67,8 @@ impl<'l, 'tcx> MirPass<'tcx> for SimplifyCfg<'l> {
 impl<'l> Pass for SimplifyCfg<'l> {}
 
 fn merge_consecutive_blocks(mir: &mut Mir) {
-    // Build the precedecessor map for the MIR
-    let mut pred_count = IndexVec::from_elem(0u32, mir.basic_blocks());
-    for (_, data) in traversal::preorder(mir) {
-        if let Some(ref term) = data.terminator {
-            for &tgt in term.successors().iter() {
-                pred_count[tgt] += 1;
-            }
-        }
-    }
+    let mut pred_count: IndexVec<_, _> =
+        mir.predecessors().iter().map(|ps| ps.len()).collect();
 
     loop {
         let mut changed = false;