Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 2b32cb9

Browse files
committedMay 2, 2017
retool MIR passes completely
The new setup is as follows. There is a pipeline of MIR passes that each run **per def-id** to optimize a particular function. You are intended to request MIR at whatever stage you need it. At the moment, there is only one stage you can request: - `optimized_mir(def_id)` This yields the final product. Internally, it pulls the MIR for the given def-id through a series of steps. Right now, these are still using an "interned ref-cell" but they are intended to "steal" from one another: - `mir_build` -- performs the initial construction for local MIR - `mir_pass_set` -- performs a suite of optimizations and transformations - `mir_pass` -- an individual optimization within a suite So, to construct the optimized MIR, we invoke: mir_pass_set((MIR_OPTIMIZED, def_id)) which will build up the final MIR.
1 parent f23a7bc commit 2b32cb9

File tree

13 files changed

+345
-185
lines changed

13 files changed

+345
-185
lines changed
 

‎src/librustc/mir/transform.rs

Lines changed: 65 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
// except according to those terms.
1010

1111
use hir;
12-
use hir::def_id::{DefId, LOCAL_CRATE};
12+
use hir::def_id::DefId;
1313
use hir::map::DefPathData;
1414
use mir::{Mir, Promoted};
1515
use ty::TyCtxt;
16+
use std::cell::{Ref, RefCell};
1617
use std::rc::Rc;
1718
use syntax::ast::NodeId;
18-
use util::common::time;
1919

2020
use std::borrow::Cow;
2121

@@ -90,12 +90,37 @@ pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
9090
}
9191
}
9292

93+
/// Gives you access to various bits of state during your MIR pass.
94+
pub trait MirCtxt<'a, 'tcx: 'a> {
95+
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx>;
96+
fn def_id(&self) -> DefId;
97+
fn pass_set(&self) -> MirPassSet;
98+
fn pass_num(&self) -> MirPassIndex;
99+
fn source(&self) -> MirSource;
100+
fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>>;
101+
fn steal_previous_mir(&self) -> &'tcx RefCell<Mir<'tcx>>;
102+
}
103+
104+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
105+
pub struct MirPassSet(pub usize);
106+
107+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
108+
pub struct MirPassIndex(pub usize);
109+
110+
/// A pass hook is invoked both before and after each pass executes.
111+
/// This is primarily used to dump MIR for debugging.
112+
///
113+
/// You can tell whether this is before or after by inspecting the
114+
/// `mir` parameter -- before the pass executes, it will be `None` (in
115+
/// which case you can inspect the MIR from previous pass by executing
116+
/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
117+
/// `Some()` with the result of the pass (in which case the output
118+
/// from the previous pass is most likely stolen, so you would not
119+
/// want to try and access it).
93120
pub trait PassHook {
94-
fn on_mir_pass<'a, 'tcx>(&self,
95-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
96-
pass_name: &str,
97-
pass_num: usize,
98-
is_after: bool);
121+
fn on_mir_pass<'a, 'tcx: 'a>(&self,
122+
mir_cx: &MirCtxt<'a, 'tcx>,
123+
mir: Option<&Mir<'tcx>>);
99124
}
100125

101126
/// A streamlined trait that you can implement to create a pass; the
@@ -107,21 +132,7 @@ pub trait DefIdPass {
107132
default_name::<Self>()
108133
}
109134

110-
fn run_pass<'a, 'tcx>(&self,
111-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
112-
def_id: DefId);
113-
}
114-
115-
impl<T: DefIdPass> Pass for T {
116-
fn name<'a>(&'a self) -> Cow<'a, str> {
117-
DefIdPass::name(self)
118-
}
119-
120-
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
121-
for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
122-
DefIdPass::run_pass(self, tcx, def_id);
123-
}
124-
}
135+
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>>;
125136
}
126137

127138
/// A streamlined trait that you can implement to create a pass; the
@@ -138,42 +149,32 @@ pub trait MirPass: DepGraphSafe {
138149
mir: &mut Mir<'tcx>);
139150
}
140151

141-
fn for_each_assoc_mir<'a, 'tcx, OP>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
142-
def_id: DefId,
143-
mut op: OP)
144-
where OP: FnMut(MirSource, &mut Mir<'tcx>)
145-
{
146-
let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
147-
let source = MirSource::from_node(tcx, id);
148-
let mir = &mut tcx.mir(def_id).borrow_mut();
149-
op(source, mir);
150-
151-
for (promoted_index, promoted_mir) in mir.promoted.iter_enumerated_mut() {
152-
let promoted_source = MirSource::Promoted(id, promoted_index);
153-
op(promoted_source, promoted_mir);
154-
}
155-
}
156-
157152
impl<T: MirPass> DefIdPass for T {
158153
fn name<'a>(&'a self) -> Cow<'a, str> {
159154
MirPass::name(self)
160155
}
161156

162-
fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) {
163-
for_each_assoc_mir(tcx, def_id, |src, mir| MirPass::run_pass(self, tcx, src, mir));
157+
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
158+
let tcx = mir_cx.tcx();
159+
let source = mir_cx.source();
160+
let mir = mir_cx.steal_previous_mir();
161+
MirPass::run_pass(self, tcx, source, &mut mir.borrow_mut());
162+
163+
let item_id = source.item_id();
164+
for (promoted_index, promoted_mir) in mir.borrow_mut().promoted.iter_enumerated_mut() {
165+
let promoted_source = MirSource::Promoted(item_id, promoted_index);
166+
MirPass::run_pass(self, tcx, promoted_source, promoted_mir);
167+
}
168+
169+
mir
164170
}
165171
}
166172

167173
/// A manager for MIR passes.
168174
#[derive(Clone)]
169175
pub struct Passes {
170176
pass_hooks: Vec<Rc<PassHook>>,
171-
sets: Vec<PassSet>,
172-
}
173-
174-
#[derive(Clone)]
175-
struct PassSet {
176-
passes: Vec<Rc<DefIdPass>>,
177+
sets: Vec<Vec<Rc<DefIdPass>>>,
177178
}
178179

179180
/// The number of "pass sets" that we have:
@@ -184,52 +185,41 @@ struct PassSet {
184185
pub const MIR_PASS_SETS: usize = 3;
185186

186187
/// Run the passes we need to do constant qualification and evaluation.
187-
pub const MIR_CONST: usize = 0;
188+
pub const MIR_CONST: MirPassSet = MirPassSet(0);
188189

189190
/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
190-
pub const MIR_VALIDATED: usize = 1;
191+
pub const MIR_VALIDATED: MirPassSet = MirPassSet(1);
191192

192193
/// Run the passes we need to consider the MIR *optimized*.
193-
pub const MIR_OPTIMIZED: usize = 2;
194+
pub const MIR_OPTIMIZED: MirPassSet = MirPassSet(2);
194195

195196
impl<'a, 'tcx> Passes {
196197
pub fn new() -> Passes {
197198
Passes {
198199
pass_hooks: Vec::new(),
199-
sets: (0..MIR_PASS_SETS).map(|_| PassSet { passes: Vec::new() }).collect(),
200-
}
201-
}
202-
203-
pub fn run_passes(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, set_index: usize) {
204-
let set = &self.sets[set_index];
205-
206-
let start_num: usize = self.sets[..set_index].iter().map(|s| s.passes.len()).sum();
207-
208-
// NB: passes are numbered from 1, since "construction" is zero.
209-
for (pass, pass_num) in set.passes.iter().zip(start_num + 1..) {
210-
for hook in &self.pass_hooks {
211-
hook.on_mir_pass(tcx, &pass.name(), pass_num, false);
212-
}
213-
214-
time(tcx.sess.time_passes(), &*pass.name(), || {
215-
for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
216-
pass.run_pass(tcx, def_id);
217-
}
218-
});
219-
220-
for hook in &self.pass_hooks {
221-
hook.on_mir_pass(tcx, &pass.name(), pass_num, true);
222-
}
200+
sets: (0..MIR_PASS_SETS).map(|_| Vec::new()).collect(),
223201
}
224202
}
225203

226204
/// Pushes a built-in pass.
227-
pub fn push_pass<T: DefIdPass + 'static>(&mut self, set: usize, pass: T) {
228-
self.sets[set].passes.push(Rc::new(pass));
205+
pub fn push_pass<T: DefIdPass + 'static>(&mut self, set: MirPassSet, pass: T) {
206+
self.sets[set.0].push(Rc::new(pass));
229207
}
230208

231209
/// Pushes a pass hook.
232210
pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
233211
self.pass_hooks.push(Rc::new(hook));
234212
}
213+
214+
pub fn len_passes(&self, set: MirPassSet) -> usize {
215+
self.sets[set.0].len()
216+
}
217+
218+
pub fn pass(&self, set: MirPassSet, pass: MirPassIndex) -> &DefIdPass {
219+
&*self.sets[set.0][pass.0]
220+
}
221+
222+
pub fn hooks(&self) -> &[Rc<PassHook>] {
223+
&self.pass_hooks
224+
}
235225
}

‎src/librustc/ty/maps.rs

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use middle::const_val;
1616
use middle::privacy::AccessLevels;
1717
use middle::region::RegionMaps;
1818
use mir;
19+
use mir::transform::{MirPassSet, MirPassIndex};
1920
use session::CompileResult;
2021
use ty::{self, CrateInherentImpls, Ty, TyCtxt};
2122
use ty::item_path;
@@ -101,6 +102,24 @@ impl<'tcx> Key for (DefId, &'tcx Substs<'tcx>) {
101102
}
102103
}
103104

105+
impl Key for (MirPassSet, DefId) {
106+
fn map_crate(&self) -> CrateNum {
107+
self.1.map_crate()
108+
}
109+
fn default_span(&self, tcx: TyCtxt) -> Span {
110+
self.1.default_span(tcx)
111+
}
112+
}
113+
114+
impl Key for (MirPassSet, MirPassIndex, DefId) {
115+
fn map_crate(&self) -> CrateNum {
116+
self.2.map_crate()
117+
}
118+
fn default_span(&self, tcx: TyCtxt) -> Span {
119+
self.2.default_span(tcx)
120+
}
121+
}
122+
104123
trait Value<'tcx>: Sized {
105124
fn from_cycle_error<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Self;
106125
}
@@ -318,6 +337,18 @@ impl<'tcx> QueryDescription for queries::is_item_mir_available<'tcx> {
318337
}
319338
}
320339

340+
impl<'tcx> QueryDescription for queries::mir_pass_set<'tcx> {
341+
fn describe(_: TyCtxt, (pass_set, _): (MirPassSet, DefId)) -> String {
342+
format!("MIR passes #{}.*", pass_set.0)
343+
}
344+
}
345+
346+
impl<'tcx> QueryDescription for queries::mir_pass<'tcx> {
347+
fn describe(_: TyCtxt, (pass_set, pass_num, _): (MirPassSet, MirPassIndex, DefId)) -> String {
348+
format!("MIR pass #{}.{}", pass_set.0, pass_num.0)
349+
}
350+
}
351+
321352
macro_rules! define_maps {
322353
(<$tcx:tt>
323354
$($(#[$attr:meta])*
@@ -542,15 +573,6 @@ define_maps! { <'tcx>
542573
/// Methods in these implementations don't need to be exported.
543574
[] inherent_impls: InherentImpls(DefId) -> Rc<Vec<DefId>>,
544575

545-
/// Maps from the def-id of a function/method or const/static
546-
/// to its MIR. Mutation is done at an item granularity to
547-
/// allow MIR optimization passes to function and still
548-
/// access cross-crate MIR (e.g. inlining or const eval).
549-
///
550-
/// Note that cross-crate MIR appears to be always borrowed
551-
/// (in the `RefCell` sense) to prevent accidental mutation.
552-
[] mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
553-
554576
/// Set of all the def-ids in this crate that have MIR associated with
555577
/// them. This includes all the body owners, but also things like struct
556578
/// constructors.
@@ -561,6 +583,26 @@ define_maps! { <'tcx>
561583
/// the value isn't known except to the pass itself.
562584
[] mir_const_qualif: Mir(DefId) -> u8,
563585

586+
/// Performs the initial MIR construction. You almost certainly do not
587+
/// want to use this query, because its output is intended to be stolen
588+
/// immediately by the MIR passes below. Consider `optimized_mir` instead.
589+
[] mir_build: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
590+
591+
/// Fetch the MIR for a given def-id after the given set of passes has ben
592+
/// applied to it. This is mostly an "intermediate" query. Normally, you would
593+
/// prefer to use `optimized_mir(def_id)`, which will fetch the MIR after all
594+
/// optimizations and so forth.
595+
[] mir_pass_set: mir_pass_set((MirPassSet, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
596+
597+
/// Fetch the MIR for a given def-id after a given pass has been executed. This is
598+
/// **only** intended to be used by the `mir_pass_set` provider -- if you are using it
599+
/// manually, you're doing it wrong.
600+
[] mir_pass: mir_pass((MirPassSet, MirPassIndex, DefId)) -> &'tcx RefCell<mir::Mir<'tcx>>,
601+
602+
/// MIR after our optimization passes have run. This is MIR that is ready
603+
/// for trans. This is also the only query that can fetch non-local MIR, at present.
604+
[] optimized_mir: Mir(DefId) -> &'tcx RefCell<mir::Mir<'tcx>>,
605+
564606
/// Records the type of each closure. The def ID is the ID of the
565607
/// expression defining the closure.
566608
[] closure_kind: ItemSignature(DefId) -> ty::ClosureKind,
@@ -658,3 +700,11 @@ fn const_eval_dep_node((def_id, _): (DefId, &Substs)) -> DepNode<DefId> {
658700
fn mir_keys(_: CrateNum) -> DepNode<DefId> {
659701
DepNode::MirKeys
660702
}
703+
704+
fn mir_pass_set((_pass_set, def_id): (MirPassSet, DefId)) -> DepNode<DefId> {
705+
DepNode::Mir(def_id)
706+
}
707+
708+
fn mir_pass((_pass_set, _pass_num, def_id): (MirPassSet, MirPassIndex, DefId)) -> DepNode<DefId> {
709+
DepNode::Mir(def_id)
710+
}

‎src/librustc/ty/mod.rs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2323,18 +2323,26 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
23232323
}
23242324
}
23252325

2326-
/// Given the did of an item, returns its MIR, borrowed immutably.
2326+
/// Given the did of an item, returns its (optimized) MIR, borrowed immutably.
23272327
pub fn item_mir(self, did: DefId) -> Ref<'gcx, Mir<'gcx>> {
2328-
self.mir(did).borrow()
2328+
self.optimized_mir(did).borrow()
23292329
}
23302330

23312331
/// Return the possibly-auto-generated MIR of a (DefId, Subst) pair.
23322332
pub fn instance_mir(self, instance: ty::InstanceDef<'gcx>)
23332333
-> Ref<'gcx, Mir<'gcx>>
23342334
{
23352335
match instance {
2336-
ty::InstanceDef::Item(did) if true => self.item_mir(did),
2337-
_ => self.mir_shims(instance).borrow(),
2336+
ty::InstanceDef::Item(did) => {
2337+
self.item_mir(did)
2338+
}
2339+
ty::InstanceDef::Intrinsic(..) |
2340+
ty::InstanceDef::FnPtrShim(..) |
2341+
ty::InstanceDef::Virtual(..) |
2342+
ty::InstanceDef::ClosureOnceShim { .. } |
2343+
ty::InstanceDef::DropGlue(..) => {
2344+
self.mir_shims(instance).borrow()
2345+
}
23382346
}
23392347
}
23402348

‎src/librustc_driver/driver.rs

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1005,11 +1005,6 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session,
10051005
mir_stats::print_mir_stats(tcx, "PRE CLEANUP MIR STATS");
10061006
}
10071007

1008-
time(time_passes, "MIR cleanup and validation", || {
1009-
tcx.mir_passes.run_passes(tcx, MIR_CONST);
1010-
tcx.mir_passes.run_passes(tcx, MIR_VALIDATED);
1011-
});
1012-
10131008
time(time_passes,
10141009
"borrow checking",
10151010
|| borrowck::check_crate(tcx));
@@ -1058,20 +1053,6 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10581053
"resolving dependency formats",
10591054
|| dependency_format::calculate(&tcx.sess));
10601055

1061-
if tcx.sess.opts.debugging_opts.mir_stats {
1062-
mir_stats::print_mir_stats(tcx, "PRE OPTIMISATION MIR STATS");
1063-
}
1064-
1065-
// Run the passes that transform the MIR into a more suitable form for translation to LLVM
1066-
// code.
1067-
time(time_passes, "MIR optimisations", || {
1068-
tcx.mir_passes.run_passes(tcx, MIR_OPTIMIZED);
1069-
});
1070-
1071-
if tcx.sess.opts.debugging_opts.mir_stats {
1072-
mir_stats::print_mir_stats(tcx, "POST OPTIMISATION MIR STATS");
1073-
}
1074-
10751056
let translation =
10761057
time(time_passes,
10771058
"translation",

‎src/librustc_metadata/cstore_impl.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ provide! { <'tcx> tcx, def_id, cdata
9595
bug!("coerce_unsized_info: `{:?}` is missing its info", def_id);
9696
})
9797
}
98-
mir => {
98+
optimized_mir => {
9999
let mir = cdata.maybe_get_item_mir(tcx, def_id.index).unwrap_or_else(|| {
100100
bug!("get_item_mir: missing MIR for `{:?}`", def_id)
101101
});

‎src/librustc_mir/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ use rustc::ty::maps::Providers;
5959
pub fn provide(providers: &mut Providers) {
6060
mir_map::provide(providers);
6161
shim::provide(providers);
62-
transform::qualify_consts::provide(providers);
62+
transform::provide(providers);
6363
}

‎src/librustc_mir/mir_map.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,11 @@ pub fn build_mir_for_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
5252
}
5353

5454
pub fn provide(providers: &mut Providers) {
55-
providers.mir = build_mir;
56-
providers.mir_keys = mir_keys;
55+
*providers = Providers {
56+
mir_build,
57+
mir_keys,
58+
..*providers
59+
};
5760
}
5861

5962
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
@@ -95,8 +98,7 @@ fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
9598
Rc::new(set)
9699
}
97100

98-
fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
99-
-> &'tcx RefCell<Mir<'tcx>> {
101+
fn mir_build<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
100102
let id = tcx.hir.as_local_node_id(def_id).unwrap();
101103
let unsupported = || {
102104
span_bug!(tcx.hir.span(id), "can't build MIR for {:?}", def_id);
@@ -192,7 +194,7 @@ fn build_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
192194
mem::transmute::<Mir, Mir<'tcx>>(mir)
193195
};
194196

195-
mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
197+
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
196198

197199
tcx.alloc_mir(mir)
198200
})
@@ -251,7 +253,7 @@ fn create_constructor_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
251253
mem::transmute::<Mir, Mir<'tcx>>(mir)
252254
};
253255

254-
mir_util::dump_mir(tcx, 0, "mir_map", &0, src, &mir);
256+
mir_util::dump_mir(tcx, None, "mir_map", &0, src, &mir);
255257

256258
tcx.alloc_mir(mir)
257259
})

‎src/librustc_mir/transform/dump_mir.rs

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
//! This pass just dumps MIR at a specified point.
1212
1313
use std::borrow::Cow;
14+
use std::cell::RefCell;
1415
use std::fmt;
1516
use std::fs::File;
1617
use std::io;
1718

18-
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
1919
use rustc::session::config::{OutputFilenames, OutputType};
2020
use rustc::ty::TyCtxt;
21-
use rustc::mir::transform::{DefIdPass, Pass, PassHook, MirSource};
21+
use rustc::mir::Mir;
22+
use rustc::mir::transform::{DefIdPass, PassHook, MirCtxt};
2223
use util as mir_util;
2324

2425
pub struct Marker(pub &'static str);
@@ -28,8 +29,8 @@ impl DefIdPass for Marker {
2829
Cow::Borrowed(self.0)
2930
}
3031

31-
fn run_pass<'a, 'tcx>(&self, _: TyCtxt<'a, 'tcx, 'tcx>, _: DefId) {
32-
// no-op
32+
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
33+
mir_cx.steal_previous_mir()
3334
}
3435
}
3536

@@ -47,30 +48,31 @@ impl fmt::Display for Disambiguator {
4748
pub struct DumpMir;
4849

4950
impl PassHook for DumpMir {
50-
fn on_mir_pass<'a, 'tcx>(
51-
&self,
52-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
53-
pass_name: &str,
54-
pass_num: usize,
55-
is_after: bool)
51+
fn on_mir_pass<'a, 'tcx: 'a>(&self,
52+
mir_cx: &MirCtxt<'a, 'tcx>,
53+
mir: Option<&Mir<'tcx>>)
5654
{
57-
// No dump filters enabled.
58-
if tcx.sess.opts.debugging_opts.dump_mir.is_none() {
59-
return;
60-
}
61-
62-
for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
63-
let id = tcx.hir.as_local_node_id(def_id).unwrap();
64-
let source = MirSource::from_node(tcx, id);
65-
let mir = tcx.item_mir(def_id);
66-
mir_util::dump_mir(
67-
tcx,
68-
pass_num,
69-
&pass_name,
70-
&Disambiguator { is_after },
71-
source,
72-
&mir
73-
);
55+
let tcx = mir_cx.tcx();
56+
let pass_set = mir_cx.pass_set();
57+
let pass_num = mir_cx.pass_num();
58+
let pass = tcx.mir_passes.pass(pass_set, pass_num);
59+
let name = &pass.name();
60+
let source = mir_cx.source();
61+
if mir_util::dump_enabled(tcx, name, source) {
62+
let previous_mir;
63+
let mir_to_dump = match mir {
64+
Some(m) => m,
65+
None => {
66+
previous_mir = mir_cx.read_previous_mir();
67+
&*previous_mir
68+
}
69+
};
70+
mir_util::dump_mir(tcx,
71+
Some((pass_set, pass_num)),
72+
name,
73+
&Disambiguator { is_after: mir.is_some() },
74+
source,
75+
mir_to_dump);
7476
}
7577
}
7678
}

‎src/librustc_mir/transform/inline.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use rustc::util::nodemap::{DefIdSet};
2727

2828
use super::simplify::{remove_dead_blocks, CfgSimplifier};
2929

30+
use std::cell::{Ref, RefCell};
3031
use syntax::{attr};
3132
use syntax::abi::Abi;
3233

@@ -74,6 +75,14 @@ struct CallSite<'tcx> {
7475
}
7576

7677
impl<'a, 'tcx> Inliner<'a, 'tcx> {
78+
fn maybe_item_mir(&mut self, _def_id: DefId) -> Option<Ref<'tcx, Mir<'tcx>>> {
79+
panic!() // TODO -- hook up inline into the system
80+
}
81+
82+
fn mir(&mut self, _def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
83+
panic!() // TODO -- hook up inline into the system
84+
}
85+
7786
fn inline_scc(&mut self, callgraph: &callgraph::CallGraph, scc: &[graph::NodeIndex]) -> bool {
7887
let mut callsites = Vec::new();
7988
let mut in_scc = DefIdSet();
@@ -146,7 +155,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
146155
self.tcx.dep_graph.write(DepNode::Mir(callsite.caller));
147156

148157
let callee_mir = {
149-
if let Some(callee_mir) = self.tcx.maybe_item_mir(callsite.callee) {
158+
if let Some(callee_mir) = self.maybe_item_mir(callsite.callee) {
150159
if !self.should_inline(callsite, &callee_mir) {
151160
continue;
152161
}
@@ -158,7 +167,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
158167

159168
};
160169

161-
let mut caller_mir = self.tcx.mir(callsite.caller).borrow_mut();
170+
let mut caller_mir = self.mir(callsite.caller).borrow_mut();
162171

163172
let start = caller_mir.basic_blocks().len();
164173

@@ -210,7 +219,7 @@ impl<'a, 'tcx> Inliner<'a, 'tcx> {
210219
let _task = self.tcx.dep_graph.in_task(DepNode::Mir(def_id));
211220
self.tcx.dep_graph.write(DepNode::Mir(def_id));
212221

213-
let mut caller_mir = self.tcx.mir(def_id).borrow_mut();
222+
let mut caller_mir = self.mir(def_id).borrow_mut();
214223

215224
debug!("Running simplify cfg on {:?}", def_id);
216225
CfgSimplifier::new(&mut caller_mir).simplify();

‎src/librustc_mir/transform/mod.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use rustc::hir::def_id::DefId;
12+
use rustc::mir::Mir;
13+
use rustc::mir::transform::{MirCtxt, MirPassIndex, MirPassSet, MirSource, MIR_OPTIMIZED};
14+
use rustc::ty::TyCtxt;
15+
use rustc::ty::maps::Providers;
16+
use std::cell::{Ref, RefCell};
17+
use std::mem;
18+
1119
pub mod simplify_branches;
1220
pub mod simplify;
1321
pub mod erase_regions;
@@ -21,3 +29,101 @@ pub mod deaggregator;
2129
pub mod instcombine;
2230
pub mod copy_prop;
2331
pub mod inline;
32+
33+
pub fn provide(providers: &mut Providers) {
34+
self::qualify_consts::provide(providers);
35+
*providers = Providers {
36+
optimized_mir,
37+
mir_pass_set,
38+
mir_pass,
39+
..*providers
40+
};
41+
}
42+
43+
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx RefCell<Mir<'tcx>> {
44+
let mir = tcx.mir_pass_set((MIR_OPTIMIZED, def_id));
45+
46+
// "lock" the ref cell into read mode; after this point,
47+
// there ought to be no more changes to the MIR.
48+
mem::drop(mir.borrow());
49+
50+
mir
51+
}
52+
53+
fn mir_pass_set<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
54+
(pass_set, def_id): (MirPassSet, DefId))
55+
-> &'tcx RefCell<Mir<'tcx>>
56+
{
57+
let passes = &tcx.mir_passes;
58+
let len = passes.len_passes(pass_set);
59+
assert!(len > 0, "no passes in {:?}", pass_set);
60+
tcx.mir_pass((pass_set, MirPassIndex(len - 1), def_id))
61+
}
62+
63+
fn mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
64+
(pass_set, pass_num, def_id): (MirPassSet, MirPassIndex, DefId))
65+
-> &'tcx RefCell<Mir<'tcx>>
66+
{
67+
let passes = &tcx.mir_passes;
68+
let pass = passes.pass(pass_set, pass_num);
69+
let mir_ctxt = MirCtxtImpl { tcx, pass_num, pass_set, def_id };
70+
71+
for hook in passes.hooks() {
72+
hook.on_mir_pass(&mir_ctxt, None);
73+
}
74+
75+
let mir = pass.run_pass(&mir_ctxt);
76+
77+
for hook in passes.hooks() {
78+
hook.on_mir_pass(&mir_ctxt, Some(&mir.borrow()));
79+
}
80+
81+
mir
82+
}
83+
84+
struct MirCtxtImpl<'a, 'tcx: 'a> {
85+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
86+
pass_num: MirPassIndex,
87+
pass_set: MirPassSet,
88+
def_id: DefId
89+
}
90+
91+
impl<'a, 'tcx> MirCtxt<'a, 'tcx> for MirCtxtImpl<'a, 'tcx> {
92+
fn tcx(&self) -> TyCtxt<'a, 'tcx, 'tcx> {
93+
self.tcx
94+
}
95+
96+
fn pass_set(&self) -> MirPassSet {
97+
self.pass_set
98+
}
99+
100+
fn pass_num(&self) -> MirPassIndex {
101+
self.pass_num
102+
}
103+
104+
fn def_id(&self) -> DefId {
105+
self.def_id
106+
}
107+
108+
fn source(&self) -> MirSource {
109+
let id = self.tcx.hir.as_local_node_id(self.def_id)
110+
.expect("mir source requires local def-id");
111+
MirSource::from_node(self.tcx, id)
112+
}
113+
114+
fn read_previous_mir(&self) -> Ref<'tcx, Mir<'tcx>> {
115+
self.steal_previous_mir().borrow()
116+
}
117+
118+
fn steal_previous_mir(&self) -> &'tcx RefCell<Mir<'tcx>> {
119+
let MirPassSet(pass_set) = self.pass_set;
120+
let MirPassIndex(pass_num) = self.pass_num;
121+
if pass_num > 0 {
122+
self.tcx.mir_pass((MirPassSet(pass_set), MirPassIndex(pass_num - 1), self.def_id))
123+
} else if pass_set > 0 {
124+
self.tcx.mir_pass_set((MirPassSet(pass_set - 1), self.def_id))
125+
} else {
126+
self.tcx.mir_build(self.def_id)
127+
}
128+
}
129+
}

‎src/librustc_mir/transform/qualify_consts.rs

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
1717
use rustc_data_structures::bitvec::BitVector;
1818
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
19-
use rustc::dep_graph::DepNode;
2019
use rustc::hir;
2120
use rustc::hir::map as hir_map;
2221
use rustc::hir::def_id::DefId;
@@ -27,13 +26,14 @@ use rustc::ty::cast::CastTy;
2726
use rustc::ty::maps::Providers;
2827
use rustc::mir::*;
2928
use rustc::mir::traversal::ReversePostorder;
30-
use rustc::mir::transform::{DefIdPass, MirSource};
29+
use rustc::mir::transform::{DefIdPass, MirCtxt, MirSource, MIR_CONST};
3130
use rustc::mir::visit::{LvalueContext, Visitor};
3231
use rustc::middle::lang_items;
3332
use syntax::abi::Abi;
3433
use syntax::feature_gate::UnstableFeatures;
3534
use syntax_pos::{Span, DUMMY_SP};
3635

36+
use std::cell::RefCell;
3737
use std::fmt;
3838
use std::usize;
3939

@@ -925,7 +925,7 @@ pub fn provide(providers: &mut Providers) {
925925
fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
926926
def_id: DefId)
927927
-> u8 {
928-
let mir = &tcx.item_mir(def_id);
928+
let mir = &tcx.mir_pass_set((MIR_CONST, def_id)).borrow();
929929
if mir.return_ty.references_error() {
930930
return Qualif::NOT_CONST.bits();
931931
}
@@ -940,30 +940,32 @@ fn qualify_const_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
940940
pub struct QualifyAndPromoteConstants;
941941

942942
impl DefIdPass for QualifyAndPromoteConstants {
943-
fn run_pass<'a, 'tcx>(&self,
944-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
945-
def_id: DefId)
946-
{
947-
let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
948-
let id = tcx.hir.as_local_node_id(def_id).unwrap();
949-
let src = MirSource::from_node(tcx, id);
950-
951-
if let MirSource::Const(_) = src {
952-
tcx.mir_const_qualif(def_id);
953-
return;
954-
}
955-
956-
let mir = &mut tcx.mir(def_id).borrow_mut();
957-
tcx.dep_graph.write(DepNode::Mir(def_id));
943+
fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>> {
944+
let tcx = mir_cx.tcx();
945+
match mir_cx.source() {
946+
MirSource::Const(_) => {
947+
// Ensure that we compute the `mir_const_qualif` for
948+
// constants at this point, before we do any further
949+
// optimization (and before we steal the previous
950+
// MIR).
951+
tcx.mir_const_qualif(mir_cx.def_id());
952+
mir_cx.steal_previous_mir()
953+
}
958954

959-
self.run_pass(tcx, src, mir);
955+
src => {
956+
let mir = mir_cx.steal_previous_mir();
957+
self.run_pass(tcx, src, &mut mir.borrow_mut());
958+
mir
959+
}
960+
}
960961
}
961962
}
962963

963964
impl<'a, 'tcx> QualifyAndPromoteConstants {
964965
fn run_pass(&self,
965966
tcx: TyCtxt<'a, 'tcx, 'tcx>,
966-
src: MirSource, mir: &mut Mir<'tcx>) {
967+
src: MirSource,
968+
mir: &mut Mir<'tcx>) {
967969
let id = src.item_id();
968970
let def_id = tcx.hir.local_def_id(id);
969971
let mode = match src {

‎src/librustc_mir/util/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ pub mod patch;
1515
mod graphviz;
1616
mod pretty;
1717

18-
pub use self::pretty::{dump_mir, write_mir_pretty};
18+
pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty};
1919
pub use self::graphviz::{write_mir_graphviz};
2020
pub use self::graphviz::write_node_label as write_graphviz_node_label;

‎src/librustc_mir/util/pretty.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
use rustc::hir;
1212
use rustc::hir::def_id::{DefId, LOCAL_CRATE};
1313
use rustc::mir::*;
14-
use rustc::mir::transform::MirSource;
14+
use rustc::mir::transform::{MirPassSet, MirPassIndex, MirSource};
1515
use rustc::ty::TyCtxt;
1616
use rustc_data_structures::fx::FxHashMap;
1717
use rustc_data_structures::indexed_vec::{Idx};
@@ -39,38 +39,45 @@ const ALIGN: usize = 40;
3939
/// that can appear in the pass-name or the `item_path_str` for the given
4040
/// node-id. If any one of the substrings match, the data is dumped out.
4141
pub fn dump_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
42-
pass_num: usize,
42+
pass_num: Option<(MirPassSet, MirPassIndex)>,
4343
pass_name: &str,
4444
disambiguator: &Display,
4545
source: MirSource,
4646
mir: &Mir<'tcx>) {
47-
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
48-
None => return,
49-
Some(ref filters) => filters,
50-
};
51-
let node_id = source.item_id();
52-
let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
53-
let is_matched =
54-
filters.split("&")
55-
.any(|filter| {
56-
filter == "all" ||
57-
pass_name.contains(filter) ||
58-
node_path.contains(filter)
59-
});
60-
if !is_matched {
47+
if !dump_enabled(tcx, pass_name, source) {
6148
return;
6249
}
6350

64-
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator, source, mir);
51+
let node_path = tcx.item_path_str(tcx.hir.local_def_id(source.item_id()));
52+
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path,
53+
disambiguator, source, mir);
6554
for (index, promoted_mir) in mir.promoted.iter_enumerated() {
6655
let promoted_source = MirSource::Promoted(source.item_id(), index);
6756
dump_matched_mir_node(tcx, pass_num, pass_name, &node_path, disambiguator,
6857
promoted_source, promoted_mir);
6958
}
7059
}
7160

61+
pub fn dump_enabled<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
62+
pass_name: &str,
63+
source: MirSource)
64+
-> bool {
65+
let filters = match tcx.sess.opts.debugging_opts.dump_mir {
66+
None => return false,
67+
Some(ref filters) => filters,
68+
};
69+
let node_id = source.item_id();
70+
let node_path = tcx.item_path_str(tcx.hir.local_def_id(node_id));
71+
filters.split("&")
72+
.any(|filter| {
73+
filter == "all" ||
74+
pass_name.contains(filter) ||
75+
node_path.contains(filter)
76+
})
77+
}
78+
7279
fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
73-
pass_num: usize,
80+
pass_num: Option<(MirPassSet, MirPassIndex)>,
7481
pass_name: &str,
7582
node_path: &str,
7683
disambiguator: &Display,
@@ -84,7 +91,10 @@ fn dump_matched_mir_node<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
8491
let pass_num = if tcx.sess.opts.debugging_opts.dump_mir_exclude_pass_number {
8592
format!("")
8693
} else {
87-
format!(".{:03}", pass_num)
94+
match pass_num {
95+
None => format!(".-------"),
96+
Some((pass_set, pass_num)) => format!(".{:03}-{:03}", pass_set.0, pass_num.0),
97+
}
8898
};
8999

90100
let mut file_path = PathBuf::new();

0 commit comments

Comments
 (0)
Please sign in to comment.