convert the inline
pass to use the new multi result
This involves changing various details about that system, though the basic shape remains the same.
This commit is contained in:
parent
1d675ce0a3
commit
a26e966307
@ -13,6 +13,8 @@ use hir::def_id::DefId;
|
||||
use hir::map::DefPathData;
|
||||
use mir::{Mir, Promoted};
|
||||
use ty::TyCtxt;
|
||||
use ty::maps::Multi;
|
||||
use ty::steal::Steal;
|
||||
use std::cell::Ref;
|
||||
use std::rc::Rc;
|
||||
use syntax::ast::NodeId;
|
||||
@ -70,15 +72,6 @@ impl<'a, 'tcx> MirSource {
|
||||
}
|
||||
}
|
||||
|
||||
/// Various information about pass.
|
||||
pub trait Pass {
|
||||
fn name<'a>(&'a self) -> Cow<'a, str> {
|
||||
default_name::<Self>()
|
||||
}
|
||||
|
||||
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>);
|
||||
}
|
||||
|
||||
/// Generates a default name for the pass based on the name of the
|
||||
/// type `T`.
|
||||
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
|
||||
@ -97,8 +90,20 @@ pub trait MirCtxt<'a, 'tcx: 'a> {
|
||||
fn suite(&self) -> MirSuite;
|
||||
fn pass_num(&self) -> MirPassIndex;
|
||||
fn source(&self) -> MirSource;
|
||||
|
||||
// Get a read-only view on the MIR of this def-id from the
|
||||
// previous pass.
|
||||
fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>;
|
||||
|
||||
// Steal the MIR of this def-id from the previous pass; any future
|
||||
// attempt to access the MIR from the previous pass is a bug.
|
||||
fn steal_previous_mir(&self) -> Mir<'tcx>;
|
||||
|
||||
// Same as `read_previous_mir()`, but for any def-id you want.
|
||||
fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>>;
|
||||
|
||||
// Same as `steal_previous_mir()`, but for any def-id you want.
|
||||
fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx>;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
@ -116,17 +121,35 @@ pub struct MirPassIndex(pub usize);
|
||||
/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
|
||||
/// `Some()` with the result of the pass (in which case the output
|
||||
/// from the previous pass is most likely stolen, so you would not
|
||||
/// want to try and access it).
|
||||
/// want to try and access it). If the pass is interprocedural, then
|
||||
/// the hook will be invoked once per output.
|
||||
pub trait PassHook {
|
||||
fn on_mir_pass<'a, 'tcx: 'a>(&self,
|
||||
mir_cx: &MirCtxt<'a, 'tcx>,
|
||||
mir: Option<&Mir<'tcx>>);
|
||||
mir: Option<(DefId, &Mir<'tcx>)>);
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create a pass; the
|
||||
/// pass will be invoked to process the MIR with the given `def_id`.
|
||||
/// This lets you do things before we fetch the MIR itself. You may
|
||||
/// prefer `MirPass`.
|
||||
/// The full suite of types that identifies a particular
|
||||
/// application of a pass to a def-id.
|
||||
pub type PassId = (MirSuite, MirPassIndex, DefId);
|
||||
|
||||
/// The most generic sort of MIR pass. You only want to implement this
|
||||
/// rather general trait if you are doing an interprocedural pass that
|
||||
/// may inspect and affect the MIR of many def-ids. Otherwise, prefer
|
||||
/// the more steamlined `DefIdPass` or `MirPass`.
|
||||
pub trait Pass {
|
||||
fn name<'a>(&'a self) -> Cow<'a, str> {
|
||||
default_name::<Self>()
|
||||
}
|
||||
|
||||
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>)
|
||||
-> Multi<PassId, &'tcx Steal<Mir<'tcx>>>;
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create an
|
||||
/// intraprocedural pass; the pass will be invoked to process the MIR
|
||||
/// with the given `def_id`. This lets you do things before we fetch
|
||||
/// the MIR itself. You may prefer `MirPass`, which is even more streamlined.
|
||||
pub trait DefIdPass {
|
||||
fn name<'a>(&'a self) -> Cow<'a, str> {
|
||||
default_name::<Self>()
|
||||
@ -135,10 +158,21 @@ pub trait DefIdPass {
|
||||
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> Mir<'tcx>;
|
||||
}
|
||||
|
||||
impl<T: DefIdPass> Pass for T {
|
||||
fn name<'a>(&'a self) -> Cow<'a, str> {
|
||||
DefIdPass::name(self)
|
||||
}
|
||||
|
||||
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>)
|
||||
-> Multi<PassId, &'tcx Steal<Mir<'tcx>>> {
|
||||
Multi::from(mir_cx.tcx().alloc_steal_mir(DefIdPass::run_pass(self, mir_cx)))
|
||||
}
|
||||
}
|
||||
|
||||
/// A streamlined trait that you can implement to create a pass; the
|
||||
/// pass will be named after the type, and it will consist of a main
|
||||
/// loop that goes over each available MIR and applies `run_pass`.
|
||||
pub trait MirPass: DepGraphSafe {
|
||||
pub trait MirPass {
|
||||
fn name<'a>(&'a self) -> Cow<'a, str> {
|
||||
default_name::<Self>()
|
||||
}
|
||||
@ -174,7 +208,7 @@ impl<T: MirPass> DefIdPass for T {
|
||||
#[derive(Clone)]
|
||||
pub struct Passes {
|
||||
pass_hooks: Vec<Rc<PassHook>>,
|
||||
suites: Vec<Vec<Rc<DefIdPass>>>,
|
||||
suites: Vec<Vec<Rc<Pass>>>,
|
||||
}
|
||||
|
||||
/// The number of "pass suites" that we have:
|
||||
@ -202,7 +236,7 @@ impl<'a, 'tcx> Passes {
|
||||
}
|
||||
|
||||
/// Pushes a built-in pass.
|
||||
pub fn push_pass<T: DefIdPass + 'static>(&mut self, suite: MirSuite, pass: T) {
|
||||
pub fn push_pass<T: Pass + 'static>(&mut self, suite: MirSuite, pass: T) {
|
||||
self.suites[suite.0].push(Rc::new(pass));
|
||||
}
|
||||
|
||||
@ -215,7 +249,7 @@ impl<'a, 'tcx> Passes {
|
||||
self.suites[suite.0].len()
|
||||
}
|
||||
|
||||
pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass {
|
||||
pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &Pass {
|
||||
&*self.suites[suite.0][pass.0]
|
||||
}
|
||||
|
||||
|
@ -24,9 +24,9 @@ use ty::steal::Steal;
|
||||
use ty::subst::Substs;
|
||||
use util::nodemap::{DefIdSet, NodeSet};
|
||||
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use std::cell::{RefCell, RefMut};
|
||||
use std::option;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::iter::{self, Once};
|
||||
@ -34,10 +34,11 @@ use std::mem;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::vec;
|
||||
use syntax_pos::{Span, DUMMY_SP};
|
||||
use syntax::symbol::Symbol;
|
||||
|
||||
trait Key: Clone + Hash + Eq + Debug {
|
||||
pub trait Key: Clone + Hash + Eq + Debug {
|
||||
fn map_crate(&self) -> CrateNum;
|
||||
fn default_span(&self, tcx: TyCtxt) -> Span;
|
||||
}
|
||||
@ -163,27 +164,61 @@ impl<'tcx> Value<'tcx> for ty::SymbolName {
|
||||
trait IntoKeyValues<K: Key, V> {
|
||||
type KeyValues: IntoIterator<Item=(K, V)>;
|
||||
|
||||
fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self::KeyValues;
|
||||
fn into_key_values(key: &K, value: Self) -> Self::KeyValues;
|
||||
}
|
||||
|
||||
impl<K: Key, V> IntoKeyValues<K, V> for V {
|
||||
type KeyValues = Once<(K, V)>;
|
||||
|
||||
fn into_key_values(_: TyCtxt, key: &K, value: Self) -> Self::KeyValues {
|
||||
fn into_key_values(key: &K, value: Self) -> Self::KeyValues {
|
||||
iter::once((key.clone(), value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Key, V> IntoKeyValues<K, V> for FxHashMap<K, V> {
|
||||
type KeyValues = Self;
|
||||
/// Return type for a multi-query, which is a query which may (if it
|
||||
/// chooses) return more than one (key, value) pair. Construct a
|
||||
/// `Multi` using `Multi::from(...)`.
|
||||
pub struct Multi<K: Key, V> {
|
||||
single: Option<V>,
|
||||
map: Vec<(K, V)>,
|
||||
}
|
||||
|
||||
fn into_key_values(tcx: TyCtxt, key: &K, value: Self) -> Self {
|
||||
if !value.contains_key(key) {
|
||||
span_bug!(key.default_span(tcx),
|
||||
"multi-generation function for `{:?}` did not generate a value for `{:?}`",
|
||||
key, key)
|
||||
impl<K: Key, V> Multi<K, V> {
|
||||
pub fn iter<'a>(&'a self, key: &'a K) -> impl Iterator<Item = (&'a K, &'a V)> + 'a {
|
||||
self.single.iter()
|
||||
.map(move |v| (key, v))
|
||||
.chain(self.map.iter().map(move |&(ref k, ref v)| (k, v)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Multi` from a single value.
|
||||
impl<K: Key, V> From<V> for Multi<K, V> {
|
||||
fn from(value: V) -> Self {
|
||||
Multi {
|
||||
single: Some(value),
|
||||
map: vec![],
|
||||
}
|
||||
value
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `Multi` from a hashmap of (K, V) pairs.
|
||||
impl<K: Key, V> From<Vec<(K, V)>> for Multi<K, V> {
|
||||
fn from(value: Vec<(K, V)>) -> Self {
|
||||
Multi {
|
||||
single: None,
|
||||
map: value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: Key, V> IntoKeyValues<K, V> for Multi<K, V> {
|
||||
type KeyValues = iter::Chain<option::IntoIter<(K, V)>, vec::IntoIter<(K, V)>>;
|
||||
|
||||
fn into_key_values(key: &K, value: Self) -> Self::KeyValues {
|
||||
value.single
|
||||
.map(|v| (key.clone(), v))
|
||||
.into_iter()
|
||||
.chain(value.map)
|
||||
}
|
||||
}
|
||||
|
||||
@ -469,7 +504,7 @@ macro_rules! define_maps {
|
||||
|
||||
{
|
||||
let map = &mut *tcx.maps.$name.borrow_mut();
|
||||
for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(tcx, &key, result) {
|
||||
for (k, v) in IntoKeyValues::<$K, $V>::into_key_values(&key, result) {
|
||||
map.insert(k, v);
|
||||
}
|
||||
}
|
||||
@ -545,16 +580,6 @@ macro_rules! define_maps {
|
||||
impl<$tcx> Clone for Providers<$tcx> {
|
||||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
|
||||
impl<$tcx> Default for Providers<$tcx> {
|
||||
fn default() -> Self {
|
||||
$(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $V {
|
||||
bug!("tcx.maps.{}({:?}) unsupported by its crate",
|
||||
stringify!($name), key);
|
||||
})*
|
||||
Providers { $($name),* }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -642,34 +667,43 @@ macro_rules! define_provider_struct {
|
||||
// Final state:
|
||||
(tcx: $tcx:tt,
|
||||
input: (),
|
||||
output: ($($output:tt)*)) => {
|
||||
output: ($(([$name:ident] [$K:ty] [$R:ty]))*)) => {
|
||||
pub struct Providers<$tcx> {
|
||||
$($output)*
|
||||
$(pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)*
|
||||
}
|
||||
|
||||
impl<$tcx> Default for Providers<$tcx> {
|
||||
fn default() -> Self {
|
||||
$(fn $name<'a, $tcx>(_: TyCtxt<'a, $tcx, $tcx>, key: $K) -> $R {
|
||||
bug!("tcx.maps.{}({:?}) unsupported by its crate",
|
||||
stringify!($name), key);
|
||||
})*
|
||||
Providers { $($name),* }
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Something ready to shift:
|
||||
(tcx: $tcx:tt,
|
||||
ready: ([$name:ident] [$K:ty] [$R:ty]),
|
||||
ready: ($name:tt $K:tt $V:tt),
|
||||
input: $input:tt,
|
||||
output: ($($output:tt)*)) => {
|
||||
define_provider_struct! {
|
||||
tcx: $tcx,
|
||||
input: $input,
|
||||
output: ($($output)*
|
||||
pub $name: for<'a> fn(TyCtxt<'a, $tcx, $tcx>, $K) -> $R,)
|
||||
output: ($($output)* ($name $K $V))
|
||||
}
|
||||
};
|
||||
|
||||
// The `multi` modifier indicates a **multiquery**, in which case
|
||||
// the function returns a `FxHashMap<K,V>` instead of just a value
|
||||
// the function returns a `Multi<K,V>` instead of just a value
|
||||
// `V`.
|
||||
(tcx: $tcx:tt,
|
||||
input: (([multi $($other_modifiers:tt)*] $name:tt [$K:ty] [$V:ty]) $($input:tt)*),
|
||||
output: $output:tt) => {
|
||||
define_provider_struct! {
|
||||
tcx: $tcx,
|
||||
ready: ($name [$K] [FxHashMap<$K,$V>]),
|
||||
ready: ($name [$K] [Multi<$K,$V>]),
|
||||
input: ($($input)*),
|
||||
output: $output
|
||||
}
|
||||
@ -778,7 +812,7 @@ define_maps! { <'tcx>
|
||||
/// Fetch the MIR for a given def-id after a given pass has been executed. This is
|
||||
/// **only** intended to be used by the `mir_suite` provider -- if you are using it
|
||||
/// manually, you're doing it wrong.
|
||||
[] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal<mir::Mir<'tcx>>,
|
||||
[multi] mir_pass: mir_pass((MirSuite, MirPassIndex, DefId)) -> &'tcx Steal<mir::Mir<'tcx>>,
|
||||
|
||||
/// MIR after our optimization passes have run. This is MIR that is ready
|
||||
/// for trans. This is also the only query that can fetch non-local MIR, at present.
|
||||
|
@ -929,7 +929,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
|
||||
passes.push_pass(MIR_OPTIMIZED, mir::transform::simplify::SimplifyCfg::new("elaborate-drops"));
|
||||
|
||||
// No lifetime analysis based on borrowing can be done from here on out.
|
||||
// passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline); // TODO re-enable
|
||||
passes.push_pass(MIR_OPTIMIZED, mir::transform::inline::Inline);
|
||||
passes.push_pass(MIR_OPTIMIZED, mir::transform::instcombine::InstCombine);
|
||||
passes.push_pass(MIR_OPTIMIZED, mir::transform::deaggregator::Deaggregator);
|
||||
passes.push_pass(MIR_OPTIMIZED, mir::transform::copy_prop::CopyPropagation);
|
||||
|
@ -22,21 +22,21 @@ use rustc::ty;
|
||||
|
||||
use rustc::util::nodemap::DefIdMap;
|
||||
|
||||
use transform::interprocedural::InterproceduralCx;
|
||||
|
||||
pub struct CallGraph {
|
||||
node_map: DefIdMap<graph::NodeIndex>,
|
||||
graph: graph::Graph<DefId, ()>
|
||||
}
|
||||
|
||||
impl CallGraph {
|
||||
// FIXME: allow for construction of a callgraph that inspects
|
||||
// cross-crate MIRs if available.
|
||||
pub fn build<'a, 'tcx>(tcx: ty::TyCtxt<'a, 'tcx, 'tcx>) -> CallGraph {
|
||||
pub fn build<'a, 'mir, 'tcx>(cx: &mut InterproceduralCx<'a, 'mir, 'tcx>) -> CallGraph {
|
||||
let mut callgraph = CallGraph {
|
||||
node_map: DefIdMap(),
|
||||
graph: graph::Graph::new()
|
||||
};
|
||||
|
||||
for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
|
||||
for &def_id in cx.tcx.mir_keys(LOCAL_CRATE).iter() {
|
||||
let idx = callgraph.add_node(def_id);
|
||||
|
||||
let mut call_visitor = CallVisitor {
|
||||
@ -44,8 +44,9 @@ impl CallGraph {
|
||||
graph: &mut callgraph
|
||||
};
|
||||
|
||||
let mir = tcx.item_mir(def_id);
|
||||
call_visitor.visit_mir(&mir);
|
||||
if let Some(mir) = cx.ensure_mir_and_read(def_id) {
|
||||
call_visitor.visit_mir(mir);
|
||||
}
|
||||
}
|
||||
|
||||
callgraph
|
||||
|
@ -15,10 +15,11 @@ use std::fmt;
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, PassHook};
|
||||
use rustc::session::config::{OutputFilenames, OutputType};
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::mir::transform::{DefIdPass, PassHook, MirCtxt};
|
||||
use util as mir_util;
|
||||
|
||||
pub struct Marker(pub &'static str);
|
||||
@ -48,19 +49,26 @@ pub struct DumpMir;
|
||||
|
||||
impl PassHook for DumpMir {
|
||||
fn on_mir_pass<'a, 'tcx: 'a>(&self,
|
||||
mir_cx: &MirCtxt<'a, 'tcx>,
|
||||
mir: Option<&Mir<'tcx>>)
|
||||
mir_cx: &MirCtxt<'a, 'tcx>,
|
||||
mir: Option<(DefId, &Mir<'tcx>)>)
|
||||
{
|
||||
let tcx = mir_cx.tcx();
|
||||
let suite = mir_cx.suite();
|
||||
let pass_num = mir_cx.pass_num();
|
||||
let pass = tcx.mir_passes.pass(suite, pass_num);
|
||||
let name = &pass.name();
|
||||
let source = mir_cx.source();
|
||||
let source = match mir {
|
||||
None => mir_cx.source(),
|
||||
Some((def_id, _)) => {
|
||||
let id = tcx.hir.as_local_node_id(def_id)
|
||||
.expect("mir source requires local def-id");
|
||||
MirSource::from_node(tcx, id)
|
||||
}
|
||||
};
|
||||
if mir_util::dump_enabled(tcx, name, source) {
|
||||
let previous_mir;
|
||||
let mir_to_dump = match mir {
|
||||
Some(m) => m,
|
||||
Some((_, m)) => m,
|
||||
None => {
|
||||
previous_mir = mir_cx.read_previous_mir();
|
||||
&*previous_mir
|
||||
|
@ -18,20 +18,22 @@ use rustc_data_structures::graph;
|
||||
|
||||
use rustc::dep_graph::DepNode;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::transform::{MirSource, Pass};
|
||||
use rustc::mir::transform::{MirCtxt, MirSource, Pass, PassId};
|
||||
use rustc::mir::visit::*;
|
||||
use rustc::traits;
|
||||
use rustc::ty::{self, Ty, TyCtxt};
|
||||
use rustc::ty::maps::Multi;
|
||||
use rustc::ty::steal::Steal;
|
||||
use rustc::ty::subst::{Subst,Substs};
|
||||
use rustc::util::nodemap::{DefIdSet};
|
||||
|
||||
use super::simplify::{remove_dead_blocks, CfgSimplifier};
|
||||
|
||||
use std::cell::{Ref, RefCell};
|
||||
use syntax::{attr};
|
||||
use syntax::abi::Abi;
|
||||
|
||||
use callgraph;
|
||||
use transform::interprocedural::InterproceduralCx;
|
||||
|
||||
const DEFAULT_THRESHOLD: usize = 50;
|
||||
const HINT_THRESHOLD: usize = 100;
|
||||
@ -44,25 +46,29 @@ const UNKNOWN_SIZE_COST: usize = 10;
|
||||
pub struct Inline;
|
||||
|
||||
impl Pass for Inline {
|
||||
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
|
||||
if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { return; }
|
||||
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>)
|
||||
-> Multi<PassId, &'tcx Steal<Mir<'tcx>>> {
|
||||
let tcx = mir_cx.tcx();
|
||||
if tcx.sess.opts.debugging_opts.mir_opt_level < 2 {
|
||||
return Multi::from(tcx.alloc_steal_mir(mir_cx.steal_previous_mir()));
|
||||
}
|
||||
|
||||
let _ignore = tcx.dep_graph.in_ignore();
|
||||
let mut cx = InterproceduralCx::new(mir_cx);
|
||||
|
||||
let callgraph = callgraph::CallGraph::build(tcx);
|
||||
let callgraph = callgraph::CallGraph::build(&mut cx);
|
||||
|
||||
let mut inliner = Inliner {
|
||||
tcx: tcx,
|
||||
};
|
||||
let mut inliner = Inliner { tcx };
|
||||
|
||||
for scc in callgraph.scc_iter() {
|
||||
inliner.inline_scc(&callgraph, &scc);
|
||||
inliner.inline_scc(&mut cx, &callgraph, &scc);
|
||||
}
|
||||
|
||||
Multi::from(cx.into_local_mirs())
|
||||
}
|
||||
}
|
||||
|
||||
struct Inliner<'a, 'tcx: 'a> {
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
struct Inliner<'mir, 'tcx: 'mir> {
|
||||
tcx: TyCtxt<'mir, 'tcx, 'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
@ -74,16 +80,12 @@ struct CallSite<'tcx> {
|
||||
location: SourceInfo,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
fn maybe_item_mir(&mut self, _def_id: DefId) -> Option<Ref<'tcx, Mir<'tcx>>> {
|
||||
panic!() // TODO -- hook up inline into the system
|
||||
}
|
||||
|
||||
fn mir(&mut self, _def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
|
||||
panic!() // TODO -- hook up inline into the system
|
||||
}
|
||||
|
||||
fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool {
|
||||
impl<'mir, 'tcx> Inliner<'mir, 'tcx> {
|
||||
fn inline_scc<'a>(&mut self,
|
||||
cx: &mut InterproceduralCx<'a, 'mir, 'tcx>,
|
||||
callgraph: &callgraph::CallGraph,
|
||||
scc: &[graph::NodeIndex]) -> bool {
|
||||
let tcx = self.tcx;
|
||||
let mut callsites = Vec::new();
|
||||
let mut in_scc = DefIdSet();
|
||||
|
||||
@ -93,14 +95,14 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
let def_id = callgraph.def_id(node);
|
||||
|
||||
// Don't inspect functions from other crates
|
||||
let id = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
|
||||
let id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
|
||||
id
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
let src = MirSource::from_node(self.tcx, id);
|
||||
let src = MirSource::from_node(tcx, id);
|
||||
if let MirSource::Fn(_) = src {
|
||||
if let Some(mir) = self.tcx.maybe_item_mir(def_id) {
|
||||
if let Some(mir) = cx.ensure_mir_and_read(def_id) {
|
||||
for (bb, bb_data) in mir.basic_blocks().iter_enumerated() {
|
||||
// Don't inline calls that are in cleanup blocks.
|
||||
if bb_data.is_cleanup { continue; }
|
||||
@ -151,27 +153,27 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
let callsite = callsites[csi];
|
||||
csi += 1;
|
||||
|
||||
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
|
||||
self.tcx.dep_graph.write(DepNode::Mir(callsite.caller));
|
||||
let _task = tcx.dep_graph.in_task(DepNode::Mir(callsite.caller));
|
||||
tcx.dep_graph.write(DepNode::Mir(callsite.caller));
|
||||
|
||||
let callee_mir = {
|
||||
if let Some(callee_mir) = self.maybe_item_mir(callsite.callee) {
|
||||
if let Some(callee_mir) = cx.ensure_mir_and_read(callsite.callee) {
|
||||
if !self.should_inline(callsite, &callee_mir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
callee_mir.subst(self.tcx, callsite.substs)
|
||||
callee_mir.subst(tcx, callsite.substs)
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
let mut caller_mir = self.mir(callsite.caller).borrow_mut();
|
||||
let caller_mir = cx.mir_mut(callsite.caller);
|
||||
|
||||
let start = caller_mir.basic_blocks().len();
|
||||
|
||||
if !self.inline_call(callsite, &mut caller_mir, callee_mir) {
|
||||
if !self.inline_call(callsite, caller_mir, callee_mir) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -216,21 +218,23 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
|
||||
// Simplify functions we inlined into.
|
||||
for def_id in inlined_into {
|
||||
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id));
|
||||
self.tcx.dep_graph.write(DepNode::Mir(def_id));
|
||||
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
|
||||
tcx.dep_graph.write(DepNode::Mir(def_id));
|
||||
|
||||
let mut caller_mir = self.mir(def_id).borrow_mut();
|
||||
let caller_mir = cx.mir_mut(def_id);
|
||||
|
||||
debug!("Running simplify cfg on {:?}", def_id);
|
||||
CfgSimplifier::new(&mut caller_mir).simplify();
|
||||
remove_dead_blocks(&mut caller_mir);
|
||||
CfgSimplifier::new(caller_mir).simplify();
|
||||
remove_dead_blocks(caller_mir);
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
fn should_inline(&self, callsite: CallSite<'tcx>,
|
||||
callee_mir: &'a Mir<'tcx>) -> bool {
|
||||
|
||||
fn should_inline(&self,
|
||||
callsite: CallSite<'tcx>,
|
||||
callee_mir: &Mir<'tcx>)
|
||||
-> bool
|
||||
{
|
||||
let tcx = self.tcx;
|
||||
|
||||
// Don't inline closures that have captures
|
||||
@ -382,10 +386,10 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn inline_call(&self, callsite: CallSite<'tcx>,
|
||||
caller_mir: &mut Mir<'tcx>, mut callee_mir: Mir<'tcx>) -> bool {
|
||||
|
||||
fn inline_call(&self,
|
||||
callsite: CallSite<'tcx>,
|
||||
caller_mir: &mut Mir<'tcx>,
|
||||
mut callee_mir: Mir<'tcx>) -> bool {
|
||||
// Don't inline a function into itself
|
||||
if callsite.caller == callsite.callee { return false; }
|
||||
|
||||
|
100
src/librustc_mir/transform/interprocedural.rs
Normal file
100
src/librustc_mir/transform/interprocedural.rs
Normal file
@ -0,0 +1,100 @@
|
||||
// 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 rustc::hir::def_id::DefId;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::mir::transform::{MirCtxt, PassId};
|
||||
use rustc::ty::steal::Steal;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
|
||||
/// When writing inter-procedural analyses etc, we need to read (and
|
||||
/// steal) the MIR for a number of def-ids at once, not all of which
|
||||
/// are local. This little cache code attempts to remember what you've
|
||||
/// stolen and so forth. It is more of a placeholder meant to get
|
||||
/// inlining up and going again, and is probably going to need heavy
|
||||
/// revision as we scale up to more interesting optimizations.
|
||||
pub struct InterproceduralCx<'a, 'mir: 'a, 'tcx: 'mir> {
|
||||
pub tcx: TyCtxt<'mir, 'tcx, 'tcx>,
|
||||
pub mir_cx: &'a MirCtxt<'mir, 'tcx>,
|
||||
local_cache: FxHashMap<DefId, Mir<'tcx>>,
|
||||
}
|
||||
|
||||
impl<'a, 'mir, 'tcx> InterproceduralCx<'a, 'mir, 'tcx> {
|
||||
pub fn new(mir_cx: &'a MirCtxt<'mir, 'tcx>) -> Self {
|
||||
InterproceduralCx {
|
||||
mir_cx,
|
||||
tcx: mir_cx.tcx(),
|
||||
local_cache: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn into_local_mirs(self) -> Vec<(PassId, &'tcx Steal<Mir<'tcx>>)> {
|
||||
let tcx = self.tcx;
|
||||
let suite = self.mir_cx.suite();
|
||||
let pass_num = self.mir_cx.pass_num();
|
||||
self.local_cache.into_iter()
|
||||
.map(|(def_id, mir)| {
|
||||
let mir = tcx.alloc_steal_mir(mir);
|
||||
((suite, pass_num, def_id), mir)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Ensures that the mir for `def_id` is available, if it can be
|
||||
/// made available.
|
||||
pub fn ensure_mir(&mut self, def_id: DefId) {
|
||||
if def_id.is_local() {
|
||||
self.ensure_mir_and_read(def_id);
|
||||
}
|
||||
}
|
||||
|
||||
/// Ensures that the mir for `def_id` is available and returns it if possible;
|
||||
/// returns `None` if this is a cross-crate MIR that is not
|
||||
/// available from metadata.
|
||||
pub fn ensure_mir_and_read(&mut self, def_id: DefId) -> Option<&Mir<'tcx>> {
|
||||
if def_id.is_local() {
|
||||
Some(self.mir_mut(def_id))
|
||||
} else {
|
||||
self.tcx.maybe_item_mir(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// True if the local cache contains MIR for `def-id`.
|
||||
pub fn contains_mir(&self, def_id: DefId) -> bool {
|
||||
if def_id.is_local() {
|
||||
self.local_cache.contains_key(&def_id)
|
||||
} else {
|
||||
self.tcx.is_item_mir_available(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the MIR for `def-id`. If the MIR is local, this will
|
||||
/// panic if you have not previously invoked `ensure_mir`.
|
||||
pub fn mir(&self, def_id: DefId) -> Option<&Mir<'tcx>> {
|
||||
if def_id.is_local() {
|
||||
match self.local_cache.get(&def_id) {
|
||||
Some(p) => Some(p),
|
||||
None => {
|
||||
panic!("MIR for local def-id `{:?}` not previously ensured", def_id)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.tcx.maybe_item_mir(def_id)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mir_mut(&mut self, def_id: DefId) -> &mut Mir<'tcx> {
|
||||
assert!(def_id.is_local(), "cannot get mutable mir of remote entry");
|
||||
let mir_cx = self.mir_cx;
|
||||
self.local_cache.entry(def_id)
|
||||
.or_insert_with(|| mir_cx.steal_previous_mir_of(def_id))
|
||||
}
|
||||
}
|
@ -10,10 +10,10 @@
|
||||
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::Mir;
|
||||
use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED};
|
||||
use rustc::mir::transform::{MirCtxt, MirPassIndex, MirSuite, MirSource, MIR_OPTIMIZED, PassId};
|
||||
use rustc::ty::steal::Steal;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::ty::maps::Providers;
|
||||
use rustc::ty::maps::{Multi, Providers};
|
||||
use std::cell::Ref;
|
||||
|
||||
pub mod simplify_branches;
|
||||
@ -29,6 +29,7 @@ pub mod deaggregator;
|
||||
pub mod instcombine;
|
||||
pub mod copy_prop;
|
||||
pub mod inline;
|
||||
pub mod interprocedural;
|
||||
|
||||
pub fn provide(providers: &mut Providers) {
|
||||
self::qualify_consts::provide(providers);
|
||||
@ -57,7 +58,7 @@ fn mir_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
(suite, pass_num, def_id): (MirSuite, MirPassIndex, DefId))
|
||||
-> &'tcx Steal<Mir<'tcx>>
|
||||
-> Multi<PassId, &'tcx Steal<Mir<'tcx>>>
|
||||
{
|
||||
let passes = &tcx.mir_passes;
|
||||
let pass = passes.pass(suite, pass_num);
|
||||
@ -69,11 +70,15 @@ fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
|
||||
let mir = pass.run_pass(&mir_ctxt);
|
||||
|
||||
let key = &(suite, pass_num, def_id);
|
||||
for hook in passes.hooks() {
|
||||
hook.on_mir_pass(&mir_ctxt, Some(&mir));
|
||||
for (&(_, _, k), v) in mir.iter(key) {
|
||||
let v = &v.borrow();
|
||||
hook.on_mir_pass(&mir_ctxt, Some((k, v)));
|
||||
}
|
||||
}
|
||||
|
||||
tcx.alloc_steal_mir(mir)
|
||||
mir
|
||||
}
|
||||
|
||||
struct MirCtxtImpl<'a, 'tcx: 'a> {
|
||||
@ -107,24 +112,32 @@ impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> {
|
||||
}
|
||||
|
||||
fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> {
|
||||
self.previous_mir().borrow()
|
||||
self.previous_mir(self.def_id).borrow()
|
||||
}
|
||||
|
||||
fn steal_previous_mir(&self) -> Mir<'tcx> {
|
||||
self.previous_mir().steal()
|
||||
self.previous_mir(self.def_id).steal()
|
||||
}
|
||||
|
||||
fn read_previous_mir_of(&self, def_id: DefId) -> Ref<'tcx, Mir<'tcx>> {
|
||||
self.previous_mir(def_id).borrow()
|
||||
}
|
||||
|
||||
fn steal_previous_mir_of(&self, def_id: DefId) -> Mir<'tcx> {
|
||||
self.previous_mir(def_id).steal()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> MirCtxtImpl<'a, 'tcx> {
|
||||
fn previous_mir(&self) -> &'tcx Steal<Mir<'tcx>> {
|
||||
fn previous_mir(&self, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
|
||||
let MirSuite(suite) = self.suite;
|
||||
let MirPassIndex(pass_num) = self.pass_num;
|
||||
if pass_num > 0 {
|
||||
self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), self.def_id))
|
||||
self.tcx.mir_pass((MirSuite(suite), MirPassIndex(pass_num - 1), def_id))
|
||||
} else if suite > 0 {
|
||||
self.tcx.mir_suite((MirSuite(suite - 1), self.def_id))
|
||||
self.tcx.mir_suite((MirSuite(suite - 1), def_id))
|
||||
} else {
|
||||
self.tcx.mir_build(self.def_id)
|
||||
self.tcx.mir_build(def_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user