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

View file

@ -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();

View file

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