Add Pass manager for MIR
This commit is contained in:
@@ -70,6 +70,7 @@ pub enum DepNode {
|
|||||||
IntrinsicCheck(DefId),
|
IntrinsicCheck(DefId),
|
||||||
MatchCheck(DefId),
|
MatchCheck(DefId),
|
||||||
MirMapConstruction(DefId),
|
MirMapConstruction(DefId),
|
||||||
|
MirPasses,
|
||||||
BorrowCheck(DefId),
|
BorrowCheck(DefId),
|
||||||
RvalueCheck(DefId),
|
RvalueCheck(DefId),
|
||||||
Reachability,
|
Reachability,
|
||||||
|
|||||||
@@ -8,31 +8,9 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use dep_graph::DepNode;
|
|
||||||
use util::nodemap::NodeMap;
|
use util::nodemap::NodeMap;
|
||||||
use mir::repr::Mir;
|
use mir::repr::Mir;
|
||||||
use mir::transform::MirPass;
|
|
||||||
use middle::ty::{self, TyCtxt};
|
|
||||||
use middle::infer;
|
|
||||||
|
|
||||||
pub struct MirMap<'tcx> {
|
pub struct MirMap<'tcx> {
|
||||||
pub map: NodeMap<Mir<'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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ impl Debug for BasicBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// BasicBlock and Terminator
|
// BasicBlockData and Terminator
|
||||||
|
|
||||||
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
|
||||||
pub struct BasicBlockData<'tcx> {
|
pub struct BasicBlockData<'tcx> {
|
||||||
|
|||||||
@@ -8,9 +8,66 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use mir::mir_map::MirMap;
|
||||||
use mir::repr::Mir;
|
use mir::repr::Mir;
|
||||||
use middle::infer::InferCtxt;
|
use middle::ty::TyCtxt;
|
||||||
|
|
||||||
pub trait MirPass {
|
/// Various information about pass.
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ use middle::cstore::CrateStore;
|
|||||||
use middle::dependency_format;
|
use middle::dependency_format;
|
||||||
use session::search_paths::PathKind;
|
use session::search_paths::PathKind;
|
||||||
use util::nodemap::{NodeMap, FnvHashMap};
|
use util::nodemap::{NodeMap, FnvHashMap};
|
||||||
use mir::transform::MirPass;
|
use mir::transform as mir_pass;
|
||||||
|
|
||||||
use syntax::ast::{NodeId, NodeIdAssigner, Name};
|
use syntax::ast::{NodeId, NodeIdAssigner, Name};
|
||||||
use syntax::codemap::{Span, MultiSpan};
|
use syntax::codemap::{Span, MultiSpan};
|
||||||
@@ -60,7 +60,7 @@ pub struct Session {
|
|||||||
pub lint_store: RefCell<lint::LintStore>,
|
pub lint_store: RefCell<lint::LintStore>,
|
||||||
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
|
pub lints: RefCell<NodeMap<Vec<(lint::LintId, Span, String)>>>,
|
||||||
pub plugin_llvm_passes: RefCell<Vec<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 plugin_attributes: RefCell<Vec<(String, AttributeType)>>,
|
||||||
pub crate_types: RefCell<Vec<config::CrateType>>,
|
pub crate_types: RefCell<Vec<config::CrateType>>,
|
||||||
pub dependency_formats: RefCell<dependency_format::Dependencies>,
|
pub dependency_formats: RefCell<dependency_format::Dependencies>,
|
||||||
@@ -477,7 +477,7 @@ pub fn build_session_(sopts: config::Options,
|
|||||||
lint_store: RefCell::new(lint::LintStore::new()),
|
lint_store: RefCell::new(lint::LintStore::new()),
|
||||||
lints: RefCell::new(NodeMap()),
|
lints: RefCell::new(NodeMap()),
|
||||||
plugin_llvm_passes: RefCell::new(Vec::new()),
|
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()),
|
plugin_attributes: RefCell::new(Vec::new()),
|
||||||
crate_types: RefCell::new(Vec::new()),
|
crate_types: RefCell::new(Vec::new()),
|
||||||
dependency_formats: RefCell::new(FnvHashMap()),
|
dependency_formats: RefCell::new(FnvHashMap()),
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rustc::dep_graph::DepGraph;
|
use rustc::dep_graph::{DepGraph, DepNode};
|
||||||
use rustc::front;
|
use rustc::front;
|
||||||
use rustc::front::map as hir_map;
|
use rustc::front::map as hir_map;
|
||||||
use rustc_mir as mir;
|
use rustc_mir as mir;
|
||||||
@@ -561,7 +561,7 @@ pub fn phase_2_configure_and_expand(sess: &Session,
|
|||||||
}
|
}
|
||||||
|
|
||||||
*sess.plugin_llvm_passes.borrow_mut() = llvm_passes;
|
*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();
|
*sess.plugin_attributes.borrow_mut() = attributes.clone();
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -861,9 +861,20 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
|||||||
"MIR dump",
|
"MIR dump",
|
||||||
|| mir::mir_map::build_mir_for_crate(tcx));
|
|| mir::mir_map::build_mir_for_crate(tcx));
|
||||||
|
|
||||||
time(time_passes,
|
time(time_passes, "MIR passes", || {
|
||||||
"MIR passes",
|
let _task = tcx.dep_graph.in_task(DepNode::MirPasses);
|
||||||
|| mir_map.run_passes(&mut sess.plugin_mir_passes.borrow_mut(), tcx));
|
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,
|
time(time_passes,
|
||||||
"borrow checking",
|
"borrow checking",
|
||||||
@@ -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
|
/// 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>,
|
pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
|
||||||
mut mir_map: MirMap<'tcx>,
|
mir_map: MirMap<'tcx>,
|
||||||
analysis: ty::CrateAnalysis)
|
analysis: ty::CrateAnalysis)
|
||||||
-> trans::CrateTranslation {
|
-> trans::CrateTranslation {
|
||||||
let time_passes = tcx.sess.time_passes();
|
let time_passes = tcx.sess.time_passes();
|
||||||
@@ -923,10 +933,6 @@ pub fn phase_4_translate_to_llvm<'tcx>(tcx: &TyCtxt<'tcx>,
|
|||||||
"resolving dependency formats",
|
"resolving dependency formats",
|
||||||
|| dependency_format::calculate(&tcx.sess));
|
|| 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.
|
// Option dance to work around the lack of stack once closures.
|
||||||
time(time_passes,
|
time(time_passes,
|
||||||
"translation",
|
"translation",
|
||||||
|
|||||||
@@ -20,16 +20,10 @@ extern crate syntax;
|
|||||||
extern crate rustc_front;
|
extern crate rustc_front;
|
||||||
|
|
||||||
use build;
|
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::dep_graph::DepNode;
|
||||||
use rustc::mir::repr::Mir;
|
use rustc::mir::repr::Mir;
|
||||||
use hair::cx::Cx;
|
use hair::cx::Cx;
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
use rustc::mir::transform::MirPass;
|
|
||||||
use rustc::mir::mir_map::MirMap;
|
use rustc::mir::mir_map::MirMap;
|
||||||
use rustc::middle::infer;
|
use rustc::middle::infer;
|
||||||
use rustc::middle::region::CodeExtentData;
|
use rustc::middle::region::CodeExtentData;
|
||||||
@@ -136,61 +130,16 @@ impl<'a, 'm, 'tcx> Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
|||||||
body: &'tcx hir::Block,
|
body: &'tcx hir::Block,
|
||||||
span: Span,
|
span: Span,
|
||||||
id: ast::NodeId) {
|
id: ast::NodeId) {
|
||||||
let (prefix, implicit_arg_tys) = match fk {
|
let implicit_arg_tys = if let intravisit::FnKind::Closure = fk {
|
||||||
intravisit::FnKind::Closure =>
|
vec![closure_self_ty(&self.tcx, id, body.id)]
|
||||||
(format!("{}-", id), vec![closure_self_ty(&self.tcx, id, body.id)]),
|
} else {
|
||||||
_ =>
|
vec![]
|
||||||
(format!(""), vec![]),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
let param_env = ty::ParameterEnvironment::for_item(self.tcx, id);
|
||||||
|
|
||||||
let infcx = infer::new_infer_ctxt(self.tcx, &self.tcx.tables, Some(param_env));
|
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) {
|
match build_mir(Cx::new(&infcx), implicit_arg_tys, id, span, decl, body) {
|
||||||
Ok(mut mir) => {
|
Ok(mir) => assert!(self.map.map.insert(id, mir).is_none()),
|
||||||
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());
|
|
||||||
}
|
|
||||||
Err(ErrorReported) => {}
|
Err(ErrorReported) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,13 +15,7 @@
|
|||||||
use rustc::middle::ty::{self, TyCtxt};
|
use rustc::middle::ty::{self, TyCtxt};
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::mir::mir_map::MirMap;
|
use rustc::mir::transform::{MirPass, Pass};
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
|
struct EraseRegionsVisitor<'a, 'tcx: 'a> {
|
||||||
tcx: &'a TyCtxt<'tcx>,
|
tcx: &'a TyCtxt<'tcx>,
|
||||||
@@ -123,3 +117,13 @@ impl<'a, 'tcx> MutVisitor<'tcx> for EraseRegionsVisitor<'a, 'tcx> {
|
|||||||
self.super_constant(constant);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
pub mod clear_dead_blocks;
|
pub mod remove_dead_blocks;
|
||||||
pub mod simplify_cfg;
|
pub mod simplify_cfg;
|
||||||
pub mod erase_regions;
|
pub mod erase_regions;
|
||||||
pub mod no_landing_pads;
|
pub mod no_landing_pads;
|
||||||
|
|||||||
@@ -11,10 +11,10 @@
|
|||||||
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
|
//! This pass removes the unwind branch of all the terminators when the no-landing-pads option is
|
||||||
//! specified.
|
//! specified.
|
||||||
|
|
||||||
use rustc::middle::infer;
|
use rustc::middle::ty::TyCtxt;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::{Pass, MirPass};
|
||||||
|
|
||||||
pub struct NoLandingPads;
|
pub struct NoLandingPads;
|
||||||
|
|
||||||
@@ -40,11 +40,12 @@ impl<'tcx> MutVisitor<'tcx> for NoLandingPads {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for NoLandingPads {
|
impl<'tcx> MirPass<'tcx> for NoLandingPads {
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>,
|
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) {
|
||||||
infcx: &infer::InferCtxt<'a, 'tcx>) {
|
if tcx.sess.no_landing_pads() {
|
||||||
if infcx.tcx.sess.no_landing_pads() {
|
|
||||||
self.visit_mir(mir);
|
self.visit_mir(mir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Pass for NoLandingPads {}
|
||||||
|
|||||||
@@ -32,50 +32,55 @@
|
|||||||
//! this pass just replaces the blocks with empty "return" blocks
|
//! this pass just replaces the blocks with empty "return" blocks
|
||||||
//! and does not renumber anything.
|
//! and does not renumber anything.
|
||||||
|
|
||||||
use rustc::middle::infer;
|
use rustc_data_structures::bitvec::BitVector;
|
||||||
|
use rustc::middle::ty::TyCtxt;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::{Pass, MirPass};
|
||||||
|
|
||||||
pub struct ClearDeadBlocks;
|
pub struct RemoveDeadBlocks;
|
||||||
|
|
||||||
impl ClearDeadBlocks {
|
|
||||||
pub fn new() -> ClearDeadBlocks {
|
|
||||||
ClearDeadBlocks
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear_dead_blocks(&self, mir: &mut Mir) {
|
|
||||||
let mut seen = vec![false; mir.basic_blocks.len()];
|
|
||||||
|
|
||||||
|
impl<'tcx> MirPass<'tcx> for RemoveDeadBlocks {
|
||||||
|
fn run_pass(&mut self, _: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) {
|
||||||
|
let mut seen = BitVector::new(mir.basic_blocks.len());
|
||||||
// These blocks are always required.
|
// These blocks are always required.
|
||||||
seen[START_BLOCK.index()] = true;
|
seen.insert(START_BLOCK.index());
|
||||||
seen[END_BLOCK.index()] = true;
|
seen.insert(END_BLOCK.index());
|
||||||
|
|
||||||
let mut worklist = vec![START_BLOCK];
|
let mut worklist = Vec::with_capacity(4);
|
||||||
|
worklist.push(START_BLOCK);
|
||||||
while let Some(bb) = worklist.pop() {
|
while let Some(bb) = worklist.pop() {
|
||||||
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
|
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
|
||||||
if !seen[succ.index()] {
|
if seen.insert(succ.index()) {
|
||||||
seen[succ.index()] = true;
|
|
||||||
worklist.push(*succ);
|
worklist.push(*succ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
retain_basic_blocks(mir, &seen);
|
||||||
for (n, (block, seen)) in mir.basic_blocks.iter_mut().zip(seen).enumerate() {
|
|
||||||
if !seen {
|
|
||||||
info!("clearing block #{}: {:?}", n, block);
|
|
||||||
*block = BasicBlockData {
|
|
||||||
statements: vec![],
|
|
||||||
terminator: Some(Terminator::Return),
|
|
||||||
is_cleanup: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for ClearDeadBlocks {
|
impl Pass for RemoveDeadBlocks {}
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>)
|
|
||||||
{
|
/// Mass removal of basic blocks to keep the ID-remapping cheap.
|
||||||
self.clear_dead_blocks(mir);
|
fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) {
|
||||||
|
let num_blocks = mir.basic_blocks.len();
|
||||||
|
|
||||||
|
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
|
||||||
|
let mut used_blocks = 0;
|
||||||
|
for alive_index in keep.iter() {
|
||||||
|
replacements[alive_index] = BasicBlock::new(used_blocks);
|
||||||
|
if alive_index != used_blocks {
|
||||||
|
// Swap the next alive block data with the current available slot. Since alive_index is
|
||||||
|
// non-decreasing this is a valid operation.
|
||||||
|
mir.basic_blocks.swap(alive_index, used_blocks);
|
||||||
|
}
|
||||||
|
used_blocks += 1;
|
||||||
|
}
|
||||||
|
mir.basic_blocks.truncate(used_blocks);
|
||||||
|
|
||||||
|
for bb in mir.all_basic_blocks() {
|
||||||
|
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
|
||||||
|
*target = replacements[target.index()];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -8,11 +8,12 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use rustc_data_structures::bitvec::BitVector;
|
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
use rustc::middle::infer;
|
use rustc::middle::ty::TyCtxt;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::{MirPass, Pass};
|
||||||
|
|
||||||
|
use super::remove_dead_blocks::RemoveDeadBlocks;
|
||||||
|
|
||||||
pub struct SimplifyCfg;
|
pub struct SimplifyCfg;
|
||||||
|
|
||||||
@@ -21,26 +22,7 @@ impl SimplifyCfg {
|
|||||||
SimplifyCfg
|
SimplifyCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_dead_blocks(&self, mir: &mut Mir) {
|
|
||||||
let mut seen = BitVector::new(mir.basic_blocks.len());
|
|
||||||
// These blocks are always required.
|
|
||||||
seen.insert(START_BLOCK.index());
|
|
||||||
seen.insert(END_BLOCK.index());
|
|
||||||
|
|
||||||
let mut worklist = Vec::with_capacity(4);
|
|
||||||
worklist.push(START_BLOCK);
|
|
||||||
while let Some(bb) = worklist.pop() {
|
|
||||||
for succ in mir.basic_block_data(bb).terminator().successors().iter() {
|
|
||||||
if seen.insert(succ.index()) {
|
|
||||||
worklist.push(*succ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
retain_basic_blocks(mir, &seen);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn remove_goto_chains(&self, mir: &mut Mir) -> bool {
|
fn remove_goto_chains(&self, mir: &mut Mir) -> bool {
|
||||||
|
|
||||||
// Find the target at the end of the jump chain, return None if there is a loop
|
// Find the target at the end of the jump chain, return None if there is a loop
|
||||||
fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
|
fn final_target(mir: &Mir, mut target: BasicBlock) -> Option<BasicBlock> {
|
||||||
// Keep track of already seen blocks to detect loops
|
// Keep track of already seen blocks to detect loops
|
||||||
@@ -118,39 +100,17 @@ impl SimplifyCfg {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for SimplifyCfg {
|
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &infer::InferCtxt<'a, 'tcx>) {
|
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, mir: &mut Mir<'tcx>) {
|
||||||
let mut changed = true;
|
let mut changed = true;
|
||||||
while changed {
|
while changed {
|
||||||
changed = self.simplify_branches(mir);
|
changed = self.simplify_branches(mir);
|
||||||
changed |= self.remove_goto_chains(mir);
|
changed |= self.remove_goto_chains(mir);
|
||||||
self.remove_dead_blocks(mir);
|
RemoveDeadBlocks.run_pass(tcx, mir);
|
||||||
}
|
}
|
||||||
// FIXME: Should probably be moved into some kind of pass manager
|
// FIXME: Should probably be moved into some kind of pass manager
|
||||||
mir.basic_blocks.shrink_to_fit();
|
mir.basic_blocks.shrink_to_fit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Mass removal of basic blocks to keep the ID-remapping cheap.
|
impl Pass for SimplifyCfg {}
|
||||||
fn retain_basic_blocks(mir: &mut Mir, keep: &BitVector) {
|
|
||||||
let num_blocks = mir.basic_blocks.len();
|
|
||||||
|
|
||||||
let mut replacements: Vec<_> = (0..num_blocks).map(BasicBlock::new).collect();
|
|
||||||
let mut used_blocks = 0;
|
|
||||||
for alive_index in keep.iter() {
|
|
||||||
replacements[alive_index] = BasicBlock::new(used_blocks);
|
|
||||||
if alive_index != used_blocks {
|
|
||||||
// Swap the next alive block data with the current available slot. Since alive_index is
|
|
||||||
// non-decreasing this is a valid operation.
|
|
||||||
mir.basic_blocks.swap(alive_index, used_blocks);
|
|
||||||
}
|
|
||||||
used_blocks += 1;
|
|
||||||
}
|
|
||||||
mir.basic_blocks.truncate(used_blocks);
|
|
||||||
|
|
||||||
for bb in mir.all_basic_blocks() {
|
|
||||||
for target in mir.basic_block_data_mut(bb).terminator_mut().successors_mut() {
|
|
||||||
*target = replacements[target.index()];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ use rustc::middle::traits;
|
|||||||
use rustc::middle::ty::{self, Ty, TyCtxt};
|
use rustc::middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc::middle::ty::fold::TypeFoldable;
|
use rustc::middle::ty::fold::TypeFoldable;
|
||||||
use rustc::mir::repr::*;
|
use rustc::mir::repr::*;
|
||||||
|
use rustc::mir::mir_map::MirMap;
|
||||||
use rustc::mir::tcx::LvalueTy;
|
use rustc::mir::tcx::LvalueTy;
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::{MirMapPass, Pass};
|
||||||
use rustc::mir::visit::{self, Visitor};
|
use rustc::mir::visit::{self, Visitor};
|
||||||
|
|
||||||
use syntax::codemap::{Span, DUMMY_SP};
|
use syntax::codemap::{Span, DUMMY_SP};
|
||||||
@@ -572,27 +573,29 @@ impl TypeckMir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MirPass for TypeckMir {
|
impl<'tcx> MirMapPass<'tcx> for TypeckMir {
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, infcx: &InferCtxt<'a, 'tcx>)
|
fn run_pass(&mut self, tcx: &TyCtxt<'tcx>, map: &mut MirMap<'tcx>) {
|
||||||
{
|
if tcx.sess.err_count() > 0 {
|
||||||
if infcx.tcx.sess.err_count() > 0 {
|
|
||||||
// compiling a broken program can obviously result in a
|
// compiling a broken program can obviously result in a
|
||||||
// broken MIR, so try not to report duplicate errors.
|
// broken MIR, so try not to report duplicate errors.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
for (&id, mir) in &mut map.map {
|
||||||
let mut checker = TypeChecker::new(infcx);
|
let param_env = ty::ParameterEnvironment::for_item(tcx, id);
|
||||||
|
let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(param_env));
|
||||||
|
let mut checker = TypeChecker::new(&infcx);
|
||||||
{
|
{
|
||||||
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
let mut verifier = TypeVerifier::new(&mut checker, mir);
|
||||||
verifier.visit_mir(mir);
|
verifier.visit_mir(mir);
|
||||||
if verifier.errors_reported {
|
if verifier.errors_reported {
|
||||||
// don't do further checks to avoid ICEs
|
// don't do further checks to avoid ICEs
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checker.typeck_mir(mir);
|
checker.typeck_mir(mir);
|
||||||
checker.verify_obligations(mir);
|
checker.verify_obligations(mir);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Pass for TypeckMir {}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
|
use rustc::lint::{EarlyLintPassObject, LateLintPassObject, LintId, Lint};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
|
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::MirMapPass;
|
||||||
|
|
||||||
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
use syntax::ext::base::{SyntaxExtension, NamedSyntaxExtension, NormalTT};
|
||||||
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
|
use syntax::ext::base::{IdentTT, MultiModifier, MultiDecorator};
|
||||||
@@ -56,7 +56,7 @@ pub struct Registry<'a> {
|
|||||||
pub late_lint_passes: Vec<LateLintPassObject>,
|
pub late_lint_passes: Vec<LateLintPassObject>,
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub mir_passes: Vec<Box<MirPass>>,
|
pub mir_passes: Vec<Box<for<'pcx> MirMapPass<'pcx>>>,
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
pub lint_groups: HashMap<&'static str, Vec<LintId>>,
|
||||||
@@ -141,7 +141,7 @@ impl<'a> Registry<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Register a MIR pass
|
/// Register a MIR pass
|
||||||
pub fn register_mir_pass(&mut self, pass: Box<MirPass>) {
|
pub fn register_mir_pass(&mut self, pass: Box<for<'pcx> MirMapPass<'pcx>>) {
|
||||||
self.mir_passes.push(pass);
|
self.mir_passes.push(pass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,17 +18,18 @@ extern crate rustc_front;
|
|||||||
extern crate rustc_plugin;
|
extern crate rustc_plugin;
|
||||||
extern crate syntax;
|
extern crate syntax;
|
||||||
|
|
||||||
use rustc::mir::transform::MirPass;
|
use rustc::mir::transform::{self, MirPass};
|
||||||
use rustc::mir::repr::{Mir, Literal};
|
use rustc::mir::repr::{Mir, Literal};
|
||||||
use rustc::mir::visit::MutVisitor;
|
use rustc::mir::visit::MutVisitor;
|
||||||
use rustc::middle::infer::InferCtxt;
|
use rustc::middle::ty;
|
||||||
use rustc::middle::const_eval::ConstVal;
|
use rustc::middle::const_eval::ConstVal;
|
||||||
use rustc_plugin::Registry;
|
use rustc_plugin::Registry;
|
||||||
|
|
||||||
struct Pass;
|
struct Pass;
|
||||||
|
|
||||||
impl MirPass for Pass {
|
impl transform::Pass for Pass {}
|
||||||
fn run_on_mir<'a, 'tcx>(&mut self, mir: &mut Mir<'tcx>, _: &InferCtxt<'a, 'tcx>) {
|
impl<'tcx> MirPass<'tcx> for Pass {
|
||||||
|
fn run_pass(&mut self, _: &ty::ctxt<'tcx>, mir: &mut Mir<'tcx>) {
|
||||||
Visitor.visit_mir(mir)
|
Visitor.visit_mir(mir)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user