Skip to content

Commit

Permalink
Add Pass manager for MIR
Browse files Browse the repository at this point in the history
  • Loading branch information
nagisa committed Mar 4, 2016
1 parent 5b5e521 commit 811b874
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 212 deletions.
1 change: 1 addition & 0 deletions src/librustc/dep_graph/mod.rs
Expand Up @@ -70,6 +70,7 @@ pub enum DepNode {
IntrinsicCheck(DefId),
MatchCheck(DefId),
MirMapConstruction(DefId),
MirPasses,
BorrowCheck(DefId),
RvalueCheck(DefId),
Reachability,
Expand Down
22 changes: 0 additions & 22 deletions src/librustc/mir/mir_map.rs
Expand Up @@ -8,31 +8,9 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use dep_graph::DepNode;
use util::nodemap::NodeMap;
use mir::repr::Mir;
use mir::transform::MirPass;
use middle::ty::{self, TyCtxt};
use middle::infer;

pub struct MirMap<'tcx> {
pub map: NodeMap<Mir<'tcx>>,
}

impl<'tcx> MirMap<'tcx> {
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &TyCtxt<'tcx>) {
if passes.is_empty() { return; }

for (&id, mir) in &mut self.map {
let did = tcx.map.local_def_id(id);
let _task = tcx.dep_graph.in_task(DepNode::MirMapConstruction(did));

let param_env = ty::ParameterEnvironment::for_item(tcx, id);
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));

for pass in &mut *passes {
pass.run_on_mir(mir, &infcx)
}
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/mir/repr.rs
Expand Up @@ -207,7 +207,7 @@ impl Debug for BasicBlock {
}

///////////////////////////////////////////////////////////////////////////
// BasicBlock and Terminator
// BasicBlockData and Terminator

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
Expand Down
63 changes: 60 additions & 3 deletions src/librustc/mir/transform.rs
Expand Up @@ -8,9 +8,66 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use mir::mir_map::MirMap;
use mir::repr::Mir;
use middle::infer::InferCtxt;
use middle::ty::TyCtxt;

pub trait MirPass {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>);
/// Various information about pass.
pub trait Pass {
// fn name() for printouts of various sorts?
// fn should_run(Session) to check if pass should run?
}

/// A pass which inspects the whole MirMap.
pub trait MirMapPass<'tcx>: Pass {
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>);
}

pub trait MirPass<'tcx>: Pass {
fn run_pass(&mut self, cx: &TyCtxt<'tcx>, map: &mut Mir<'tcx>);
}

impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
for (_, mir) in &mut map.map {
MirPass::run_pass(self, tcx, mir);
}
}
}

/// A manager for MIR passes.
pub struct Passes {
passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
}

impl Passes {
pub fn new() -> Passes {
let passes = Passes {
passes: Vec::new(),
plugin_passes: Vec::new()
};
passes
}

pub fn run_passes<'tcx>(&mut self, pcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
for pass in &mut self.plugin_passes {
pass.run_pass(pcx, map);
}
for pass in &mut self.passes {
pass.run_pass(pcx, map);
}
}

/// Pushes a built-in pass.
pub fn push_pass(&mut self, pass: Box<for<'a> MirMapPass<'a>>) {
self.passes.push(pass);
}
}

/// Copies the plugin passes.
impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
self.plugin_passes.extend(it);
}
}
6 changes: 3 additions & 3 deletions src/librustc/session/mod.rs
Expand Up @@ -13,7 +13,7 @@ use middle::cstore::CrateStore;
use middle::dependency_format;
use session::search_paths::PathKind;
use util::nodemap::{NodeMap, FnvHashMap};
use mir::transform::MirPass;
use mir::transform as mir_pass;

use syntax::ast::{NodeId, NodeIdAssigner, Name};
use syntax::codemap::{Span, MultiSpan};
Expand Down Expand Up @@ -60,7 +60,7 @@ pub struct Session {
pub lint_store: RefCell<lint::LintStore>,
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
pub plugin_llvm_passes: RefCell<Vec<String>>,
pub plugin_mir_passes: RefCell<Vec<Box<MirPass>>>,
pub mir_passes: RefCell<mir_pass::Passes>,
pub plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
pub crate_types: RefCell<Vec<config::CrateType>>,
pub dependency_formats: RefCell<dependency_format::Dependencies>,
Expand Down Expand Up @@ -477,7 +477,7 @@ pub fn build_session_(sopts: config::Options,
lint_store: RefCell::new(lint::LintStore::new()),
lints: RefCell::new(NodeMap()),
plugin_llvm_passes: RefCell::new(Vec::new()),
plugin_mir_passes: RefCell::new(Vec::new()),
mir_passes: RefCell::new(mir_pass::Passes::new()),
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FnvHashMap()),
Expand Down
28 changes: 17 additions & 11 deletions src/librustc_driver/driver.rs
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::dep_graph::DepGraph;
use rustc::dep_graph::{DepGraph, DepNode};
use rustc::front;
use rustc::front::map as hir_map;
use rustc_mir as mir;
Expand Down Expand Up @@ -561,7 +561,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
}

*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
*sess.plugin_mir_passes.borrow_mut() = mir_passes;
sess.mir_passes.borrow_mut().extend(mir_passes);
*sess.plugin_attributes.borrow_mut() = attributes.clone();
}));

Expand Down Expand Up @@ -861,9 +861,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
"MIR dump",
|| mir::mir_map::build_mir_for_crate(tcx));

time(time_passes,
"MIR passes",
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
time(time_passes, "MIR passes", || {
let _task = tcx.dep_graph.in_task(DepNode::MirPasses);
let mut passes = sess.mir_passes.borrow_mut();
// Push all the built-in passes.
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
passes.push_pass(box mir::transform::type_check::TypeckMir);
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg);
// Late passes
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
passes.push_pass(box mir::transform::remove_dead_blocks::RemoveDeadBlocks);
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
// And run everything.
passes.run_passes(tcx, &mut mir_map);
});

time(time_passes,
"borrow checking",
Expand Down Expand Up @@ -912,9 +923,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
}

/// Run the translation phase to LLVM, after which the AST and analysis can
/// be discarded.
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
mut mir_map: MirMap<'tcx>,
mir_map: MirMap<'tcx>,
analysis: ty::CrateAnalysis)
-> trans::CrateTranslation {
let time_passes = tcx.sess.time_passes();
Expand All @@ -923,10 +933,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
"resolving dependency formats",
|| dependency_format::calculate(&tcx.sess));

time(time_passes,
"erasing regions from MIR",
|| mir::transform::erase_regions::erase_regions(tcx, &mut mir_map));

// Option dance to work around the lack of stack once closures.
time(time_passes,
"translation",
Expand Down
61 changes: 5 additions & 56 deletions src/librustc_mir/mir_map.rs
Expand Up @@ -20,16 +20,10 @@ extern crate syntax;
extern crate rustc_front;

use build;
use graphviz;
use pretty;
use transform::{clear_dead_blocks, simplify_cfg, type_check};
use transform::{no_landing_pads};
use rustc::dep_graph::DepNode;
use rustc::mir::repr::Mir;
use hair::cx::Cx;
use std::fs::File;

use rustc::mir::transform::MirPass;
use rustc::mir::mir_map::MirMap;
use rustc::middle::infer;
use rustc::middle::region::CodeExtentData;
Expand Down Expand Up @@ -136,61 +130,16 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
body: &'tcx hir::Block,
span: Span,
id: ast::NodeId) {
let (prefix, implicit_arg_tys) = match fk {
intravisit::FnKind::Closure =>
(format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
_ =>
(format!(""), vec![]),
let implicit_arg_tys = if let intravisit::FnKind::Closure = fk {
vec![closure_self_ty(&self.tcx, id, body.id)]
} else {
vec![]
};

let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);

let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));

match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
Ok(mut mir) => {
clear_dead_blocks::ClearDeadBlocks::new().run_on_mir(&mut mir, &infcx);
type_check::TypeckMir::new().run_on_mir(&mut mir, &infcx);
no_landing_pads::NoLandingPads.run_on_mir(&mut mir, &infcx);
if self.tcx.sess.opts.mir_opt_level > 0 {
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, &infcx);
}
let meta_item_list = self.attr
.iter()
.flat_map(|a| a.meta_item_list())
.flat_map(|l| l.iter());
for item in meta_item_list {
if item.check_name("graphviz") || item.check_name("pretty") {
match item.value_str() {
Some(s) => {
let filename = format!("{}{}", prefix, s);
let result = File::create(&filename).and_then(|ref mut output| {
if item.check_name("graphviz") {
graphviz::write_mir_graphviz(&mir, output)
} else {
pretty::write_mir_pretty(&mir, output)
}
});

if let Err(e) = result {
self.tcx.sess.span_fatal(
item.span,
&format!("Error writing MIR {} results to `{}`: {}",
item.name(), filename, e));
}
}
None => {
self.tcx.sess.span_err(
item.span,
&format!("{} attribute requires a path", item.name()));
}
}
}
}

let previous = self.map.map.insert(id, mir);
assert!(previous.is_none());
}
Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
Err(ErrorReported) => {}
}

Expand Down
18 changes: 11 additions & 7 deletions src/librustc_mir/transform/erase_regions.rs
Expand Up @@ -15,13 +15,7 @@
use rustc::middle::ty::{self, TyCtxt};
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::mir_map::MirMap;

pub fn erase_regions<'tcx>(tcx: &TyCtxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
for (_, mir) in &mut mir_map.map {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}
use rustc::mir::transform::{MirPass, Pass};

struct EraseRegionsVisitor<'a, 'tcx: 'a> {
tcx: &'a TyCtxt<'tcx>,
Expand Down Expand Up @@ -123,3 +117,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
self.super_constant(constant);
}
}

pub struct EraseRegions;

impl Pass for EraseRegions {}

impl<'tcx> MirPass<'tcx> for EraseRegions {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}
2 changes: 1 addition & 1 deletion src/librustc_mir/transform/mod.rs
Expand Up @@ -8,7 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

pub mod clear_dead_blocks;
pub mod remove_dead_blocks;
pub mod simplify_cfg;
pub mod erase_regions;
pub mod no_landing_pads;
Expand Down
13 changes: 7 additions & 6 deletions src/librustc_mir/transform/no_landing_pads.rs
Expand Up @@ -11,10 +11,10 @@
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
//! specified.

use rustc::middle::infer;
use rustc::middle::ty::TyCtxt;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::transform::MirPass;
use rustc::mir::transform::{Pass, MirPass};

pub struct NoLandingPads;

Expand All @@ -40,11 +40,12 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
}
}

impl MirPass for NoLandingPads {
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>,
infcx: &infer::InferCtxt<'a, 'tcx>) {
if infcx.tcx.sess.no_landing_pads() {
impl<'tcx> MirPass<'tcx> for NoLandingPads {
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) {
if tcx.sess.no_landing_pads() {
self.visit_mir(mir);
}
}
}

impl Pass for NoLandingPads {}

0 comments on commit 811b874

Please sign in to comment.