add a cache for MIR predecessors

This commit is contained in:
Ariel Ben-Yehuda 2016-06-07 22:02:08 +03:00 committed by Ariel Ben-Yehuda
parent e3af9fa490
commit 6405527ded
5 changed files with 93 additions and 21 deletions

View file

@ -102,6 +102,7 @@ pub mod middle {
}
pub mod mir {
mod cache;
pub mod repr;
pub mod tcx;
pub mod visit;

69
src/librustc/mir/cache.rs Normal file
View file

@ -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
}

View file

@ -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> {