Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RFC-ish][MIR] Add a pass manager #31448

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc/dep_graph/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ pub enum DepNode {
IntrinsicCheck(DefId),
MatchCheck(DefId),
MirMapConstruction(DefId),
MirPrintPass,
BorrowCheck(DefId),
RvalueCheck(DefId),
Reachability,
Expand Down
12 changes: 0 additions & 12 deletions src/librustc/mir/mir_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,7 @@

use util::nodemap::NodeMap;
use mir::repr::Mir;
use mir::transform::MirPass;
use middle::ty;

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

impl<'tcx> MirMap<'tcx> {
pub fn run_passes(&mut self, passes: &mut [Box<MirPass>], tcx: &ty::ctxt<'tcx>) {
for (_, ref mut mir) in &mut self.map {
for pass in &mut *passes {
pass.run_on_mir(mir, tcx)
}
}
}
}
2 changes: 1 addition & 1 deletion src/librustc/mir/repr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ impl Debug for BasicBlock {
}

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

#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
pub struct BasicBlockData<'tcx> {
Expand Down
54 changes: 52 additions & 2 deletions src/librustc/mir/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,58 @@
// except according to those terms.

use mir::repr::Mir;
use mir::mir_map::MirMap;
use middle::ty::ctxt;

pub trait MirPass {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ctxt<'tcx>);
/// Contains various metadata about the pass.
pub trait Pass {
// Possibly also `fn name()` and `fn should_run(Session)` etc.
}

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

/// Pass which only inspects MIR of distinct functions.
pub trait MirPass<'tcx>: Pass {
fn run_pass(&mut self, tcx: &ctxt<'tcx>, mir: &mut Mir<'tcx>);
}

impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
fn run_pass(&mut self, tcx: &ctxt<'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>>>
}

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

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

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

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.passes.extend(it);
}
}
6 changes: 3 additions & 3 deletions src/librustc/session/mod.rs
Original file line number Diff line number Diff line change
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;

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::transform::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::transform::Passes::new()),
plugin_attributes: RefCell::new(Vec::new()),
crate_types: RefCell::new(Vec::new()),
dependency_formats: RefCell::new(FnvHashMap()),
Expand Down
29 changes: 16 additions & 13 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use rustc::middle;
use rustc::util::common::time;
use rustc::util::nodemap::NodeSet;
use rustc_borrowck as borrowck;
use rustc_mir::transform;
use rustc_resolve as resolve;
use rustc_metadata::macro_import;
use rustc_metadata::creader::LocalCrateReader;
Expand Down Expand Up @@ -561,8 +562,8 @@ 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.plugin_attributes.borrow_mut() = attributes.clone();
sess.mir_passes.borrow_mut().extend(mir_passes);
}));

// Lint plugins are registered; now we can process command line flags.
Expand Down Expand Up @@ -846,12 +847,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,

let mut mir_map =
time(time_passes,
"MIR dump",
"MIR build",
|| 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 mut passes = sess.mir_passes.borrow_mut();
// Push all the built-in passes.
passes.push_pass(box transform::simplify_cfg::SimplifyCfg);
passes.push_pass(box transform::erase_regions::EraseRegions);
passes.push_pass(box transform::print::MirPrint);
passes.push_pass(box transform::simplify_cfg::CompactMir);
// And run everything.
passes.run_passes(tcx, &mut mir_map);
});

time(time_passes,
"liveness checking",
Expand Down Expand Up @@ -907,10 +916,9 @@ 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.
/// Run the translation phase to LLVM, after which the MIR and analysis can be discarded.
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>,
mut mir_map: MirMap<'tcx>,
mir_map: MirMap<'tcx>,
analysis: ty::CrateAnalysis)
-> trans::CrateTranslation {
let time_passes = tcx.sess.time_passes();
Expand All @@ -919,11 +927,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'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",
move || trans::trans_crate(tcx, &mir_map, analysis))
Expand Down
64 changes: 5 additions & 59 deletions src/librustc_mir/mir_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,27 +8,16 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! An experimental pass that scources for `#[rustc_mir]` attributes,
//! builds the resulting MIR, and dumps it out into a file for inspection.
//!
//! The attribute formats that are currently accepted are:
//!
//! - `#[rustc_mir(graphviz="file.gv")]`
//! - `#[rustc_mir(pretty="file.mir")]`
//! An pass that builds the MIR for each item and stores it into the map.

extern crate syntax;
extern crate rustc_front;

use build;
use graphviz;
use pretty;
use transform::simplify_cfg;
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 @@ -135,57 +124,14 @@ 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 = match fk {
intravisit::FnKind::Closure => vec![closure_self_ty(&self.tcx, id, body.id)],
_ => 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) => {
simplify_cfg::SimplifyCfg::new().run_on_mir(&mut mir, self.tcx);

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
20 changes: 12 additions & 8 deletions src/librustc_mir/transform/erase_regions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,28 @@ use rustc::middle::ty;
use rustc::mir::repr::*;
use rustc::mir::visit::MutVisitor;
use rustc::mir::mir_map::MirMap;
use rustc::mir::transform::MirPass;
use rustc::mir::transform::{MirPass, Pass};

pub fn erase_regions<'tcx>(tcx: &ty::ctxt<'tcx>, mir_map: &mut MirMap<'tcx>) {
let mut eraser = EraseRegions;

for (_, mir) in &mut mir_map.map {
eraser.run_on_mir(mir, tcx);
eraser.run_pass(tcx, mir);
}
}

pub struct EraseRegions;

impl<'tcx> MirPass<'tcx> for EraseRegions {
fn run_pass(&mut self, tcx: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}

}

impl Pass for EraseRegions {
}

struct EraseRegionsVisitor<'a, 'tcx: 'a> {
tcx: &'a ty::ctxt<'tcx>,
}
Expand Down Expand Up @@ -58,12 +68,6 @@ impl<'a, 'tcx> EraseRegionsVisitor<'a, 'tcx> {
}
}

impl MirPass for EraseRegions {
fn run_on_mir<'tcx>(&mut self, mir: &mut Mir<'tcx>, tcx: &ty::ctxt<'tcx>) {
EraseRegionsVisitor::new(tcx).visit_mir(mir);
}
}

impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
fn visit_mir(&mut self, mir: &mut Mir<'tcx>) {
self.erase_regions_return_ty(&mut mir.return_ty);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@

pub mod simplify_cfg;
pub mod erase_regions;
pub mod print;
mod util;
Loading