Skip to content

Commit c5022f2

Browse files
committed
rustc_mir: drive passes directly with a macro.
1 parent 86206f2 commit c5022f2

File tree

4 files changed

+108
-220
lines changed

4 files changed

+108
-220
lines changed

src/librustc_mir/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
2121
#![feature(conservative_impl_trait)]
2222
#![feature(const_fn)]
2323
#![feature(core_intrinsics)]
24+
#![feature(decl_macro)]
2425
#![feature(i128_type)]
2526
#![feature(rustc_diagnostic_macros)]
2627
#![feature(placement_in_syntax)]

src/librustc_mir/transform/dump_mir.rs

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use rustc::mir::Mir;
1919
use rustc::mir::transform::MirSource;
2020
use rustc::session::config::{OutputFilenames, OutputType};
2121
use rustc::ty::TyCtxt;
22-
use transform::{MirPass, MirPassIndex, MirSuite, PassHook};
22+
use transform::MirPass;
2323
use util as mir_util;
2424

2525
pub struct Marker(pub &'static str);
@@ -48,37 +48,21 @@ impl fmt::Display for Disambiguator {
4848
}
4949
}
5050

51-
pub struct DumpMir;
5251

53-
impl PassHook for DumpMir {
54-
fn on_mir_pass<'a, 'tcx: 'a>(&self,
55-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
56-
suite: MirSuite,
57-
pass_num: MirPassIndex,
58-
pass_name: &str,
59-
source: MirSource,
60-
mir: &Mir<'tcx>,
61-
is_after: bool)
62-
{
63-
if mir_util::dump_enabled(tcx, pass_name, source) {
64-
mir_util::dump_mir(tcx,
65-
Some((suite, pass_num)),
66-
pass_name,
67-
&Disambiguator { is_after },
68-
source,
69-
mir,
70-
|_, _| Ok(()) );
71-
for (index, promoted_mir) in mir.promoted.iter_enumerated() {
72-
let promoted_source = MirSource::Promoted(source.item_id(), index);
73-
mir_util::dump_mir(tcx,
74-
Some((suite, pass_num)),
75-
pass_name,
76-
&Disambiguator { is_after },
77-
promoted_source,
78-
promoted_mir,
79-
|_, _| Ok(()) );
80-
}
81-
}
52+
pub fn on_mir_pass<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
53+
pass_num: &fmt::Display,
54+
pass_name: &str,
55+
source: MirSource,
56+
mir: &Mir<'tcx>,
57+
is_after: bool) {
58+
if mir_util::dump_enabled(tcx, pass_name, source) {
59+
mir_util::dump_mir(tcx,
60+
Some(pass_num),
61+
pass_name,
62+
&Disambiguator { is_after },
63+
source,
64+
mir,
65+
|_, _| Ok(()) );
8266
}
8367
}
8468

src/librustc_mir/transform/mod.rs

Lines changed: 89 additions & 185 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use std::borrow::Cow;
2222
use std::rc::Rc;
2323
use syntax::ast;
2424
use syntax_pos::Span;
25-
use transform;
2625

2726
pub mod add_validation;
2827
pub mod clean_end_regions;
@@ -109,41 +108,6 @@ fn mir_built<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Stea
109108
tcx.alloc_steal_mir(mir)
110109
}
111110

112-
fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
113-
// Unsafety check uses the raw mir, so make sure it is run
114-
let _ = tcx.unsafety_check_result(def_id);
115-
116-
let source = MirSource::from_local_def_id(tcx, def_id);
117-
let mut mir = tcx.mir_built(def_id).steal();
118-
transform::run_suite(tcx, source, MIR_CONST, &mut mir);
119-
tcx.alloc_steal_mir(mir)
120-
}
121-
122-
fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
123-
let source = MirSource::from_local_def_id(tcx, def_id);
124-
if let MirSource::Const(_) = source {
125-
// Ensure that we compute the `mir_const_qualif` for constants at
126-
// this point, before we steal the mir-const result.
127-
let _ = tcx.mir_const_qualif(def_id);
128-
}
129-
130-
let mut mir = tcx.mir_const(def_id).steal();
131-
transform::run_suite(tcx, source, MIR_VALIDATED, &mut mir);
132-
tcx.alloc_steal_mir(mir)
133-
}
134-
135-
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
136-
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
137-
// execute before we can steal.
138-
let _ = tcx.mir_borrowck(def_id);
139-
let _ = tcx.borrowck(def_id);
140-
141-
let mut mir = tcx.mir_validated(def_id).steal();
142-
let source = MirSource::from_local_def_id(tcx, def_id);
143-
transform::run_suite(tcx, source, MIR_OPTIMIZED, &mut mir);
144-
tcx.alloc_mir(mir)
145-
}
146-
147111
/// Generates a default name for the pass based on the name of the
148112
/// type `T`.
149113
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
@@ -155,38 +119,6 @@ pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
155119
}
156120
}
157121

158-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
159-
pub struct MirSuite(pub usize);
160-
161-
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
162-
pub struct MirPassIndex(pub usize);
163-
164-
/// A pass hook is invoked both before and after each pass executes.
165-
/// This is primarily used to dump MIR for debugging.
166-
///
167-
/// You can tell whether this is before or after by inspecting the
168-
/// `mir` parameter -- before the pass executes, it will be `None` (in
169-
/// which case you can inspect the MIR from previous pass by executing
170-
/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
171-
/// `Some()` with the result of the pass (in which case the output
172-
/// from the previous pass is most likely stolen, so you would not
173-
/// want to try and access it). If the pass is interprocedural, then
174-
/// the hook will be invoked once per output.
175-
pub trait PassHook {
176-
fn on_mir_pass<'a, 'tcx: 'a>(&self,
177-
tcx: TyCtxt<'a, 'tcx, 'tcx>,
178-
suite: MirSuite,
179-
pass_num: MirPassIndex,
180-
pass_name: &str,
181-
source: MirSource,
182-
mir: &Mir<'tcx>,
183-
is_after: bool);
184-
}
185-
186-
/// The full suite of types that identifies a particular
187-
/// application of a pass to a def-id.
188-
pub type PassId = (MirSuite, MirPassIndex, DefId);
189-
190122
/// A streamlined trait that you can implement to create a pass; the
191123
/// pass will be named after the type, and it will consist of a main
192124
/// loop that goes over each available MIR and applies `run_pass`.
@@ -201,132 +133,104 @@ pub trait MirPass {
201133
mir: &mut Mir<'tcx>);
202134
}
203135

204-
/// A manager for MIR passes.
205-
///
206-
/// FIXME(#41712) -- it is unclear whether we should have this struct.
207-
#[derive(Clone)]
208-
pub struct Passes {
209-
pass_hooks: Vec<Rc<PassHook>>,
210-
suites: Vec<Vec<Rc<MirPass>>>,
211-
}
212-
213-
/// The number of "pass suites" that we have:
214-
///
215-
/// - ready for constant evaluation
216-
/// - unopt
217-
/// - optimized
218-
pub const MIR_SUITES: usize = 3;
219-
220-
/// Run the passes we need to do constant qualification and evaluation.
221-
pub const MIR_CONST: MirSuite = MirSuite(0);
222-
223-
/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
224-
pub const MIR_VALIDATED: MirSuite = MirSuite(1);
136+
pub macro run_passes($tcx:ident, $mir:ident, $source:ident, $suite_index:expr; $($pass:expr,)*) {{
137+
let suite_index: usize = $suite_index;
138+
let run_passes = |mir: &mut _, source| {
139+
let mut index = 0;
140+
let mut run_pass = |pass: &MirPass| {
141+
let run_hooks = |mir: &_, index, is_after| {
142+
dump_mir::on_mir_pass($tcx, &format_args!("{:03}-{:03}", suite_index, index),
143+
&pass.name(), source, mir, is_after);
144+
};
145+
run_hooks(mir, index, false);
146+
pass.run_pass($tcx, source, mir);
147+
run_hooks(mir, index, true);
148+
149+
index += 1;
150+
};
151+
$(run_pass(&$pass);)*
152+
};
153+
run_passes(&mut $mir, $source);
225154

226-
/// Run the passes we need to consider the MIR *optimized*.
227-
pub const MIR_OPTIMIZED: MirSuite = MirSuite(2);
155+
for (index, promoted_mir) in $mir.promoted.iter_enumerated_mut() {
156+
run_passes(promoted_mir, MirSource::Promoted($source.item_id(), index));
228157

229-
impl<'a, 'tcx> Passes {
230-
pub fn new() -> Passes {
231-
Passes {
232-
pass_hooks: Vec::new(),
233-
suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(),
234-
}
158+
// Let's make sure we don't miss any nested instances
159+
assert!(promoted_mir.promoted.is_empty());
235160
}
161+
}}
236162

237-
/// Pushes a built-in pass.
238-
pub fn push_pass<T: MirPass + 'static>(&mut self, suite: MirSuite, pass: T) {
239-
self.suites[suite.0].push(Rc::new(pass));
240-
}
163+
fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
164+
// Unsafety check uses the raw mir, so make sure it is run
165+
let _ = tcx.unsafety_check_result(def_id);
241166

242-
/// Pushes a pass hook.
243-
pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
244-
self.pass_hooks.push(Rc::new(hook));
245-
}
167+
let mut mir = tcx.mir_built(def_id).steal();
168+
let source = MirSource::from_local_def_id(tcx, def_id);
169+
run_passes![tcx, mir, source, 0;
170+
// Remove all `EndRegion` statements that are not involved in borrows.
171+
clean_end_regions::CleanEndRegions,
172+
173+
// What we need to do constant evaluation.
174+
simplify::SimplifyCfg::new("initial"),
175+
type_check::TypeckMir,
176+
rustc_peek::SanityCheck,
177+
];
178+
tcx.alloc_steal_mir(mir)
179+
}
246180

247-
pub fn passes(&self, suite: MirSuite) -> &[Rc<MirPass>] {
248-
&self.suites[suite.0]
181+
fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
182+
let source = MirSource::from_local_def_id(tcx, def_id);
183+
if let MirSource::Const(_) = source {
184+
// Ensure that we compute the `mir_const_qualif` for constants at
185+
// this point, before we steal the mir-const result.
186+
let _ = tcx.mir_const_qualif(def_id);
249187
}
250188

251-
pub fn hooks(&self) -> &[Rc<PassHook>] {
252-
&self.pass_hooks
253-
}
189+
let mut mir = tcx.mir_const(def_id).steal();
190+
run_passes![tcx, mir, source, 1;
191+
// What we need to run borrowck etc.
192+
qualify_consts::QualifyAndPromoteConstants,
193+
simplify::SimplifyCfg::new("qualify-consts"),
194+
];
195+
tcx.alloc_steal_mir(mir)
254196
}
255197

256-
fn run_suite<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
257-
source: MirSource,
258-
suite: MirSuite,
259-
mir: &mut Mir<'tcx>)
260-
{
261-
// Setup the MIR passes that we want to run.
262-
let mut passes = Passes::new();
263-
passes.push_hook(dump_mir::DumpMir);
264-
265-
// Remove all `EndRegion` statements that are not involved in borrows.
266-
passes.push_pass(MIR_CONST, clean_end_regions::CleanEndRegions);
267-
268-
// What we need to do constant evaluation.
269-
passes.push_pass(MIR_CONST, simplify::SimplifyCfg::new("initial"));
270-
passes.push_pass(MIR_CONST, type_check::TypeckMir);
271-
passes.push_pass(MIR_CONST, rustc_peek::SanityCheck);
272-
273-
// We compute "constant qualifications" between MIR_CONST and MIR_VALIDATED.
274-
275-
// What we need to run borrowck etc.
276-
277-
passes.push_pass(MIR_VALIDATED, qualify_consts::QualifyAndPromoteConstants);
278-
passes.push_pass(MIR_VALIDATED, simplify::SimplifyCfg::new("qualify-consts"));
279-
280-
// borrowck runs between MIR_VALIDATED and MIR_OPTIMIZED.
281-
282-
passes.push_pass(MIR_OPTIMIZED, no_landing_pads::NoLandingPads);
283-
passes.push_pass(MIR_OPTIMIZED,
284-
simplify_branches::SimplifyBranches::new("initial"));
285-
286-
// These next passes must be executed together
287-
passes.push_pass(MIR_OPTIMIZED, add_call_guards::CriticalCallEdges);
288-
passes.push_pass(MIR_OPTIMIZED, elaborate_drops::ElaborateDrops);
289-
passes.push_pass(MIR_OPTIMIZED, no_landing_pads::NoLandingPads);
290-
// AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
291-
// an AllCallEdges pass right before it.
292-
passes.push_pass(MIR_OPTIMIZED, add_call_guards::AllCallEdges);
293-
passes.push_pass(MIR_OPTIMIZED, add_validation::AddValidation);
294-
passes.push_pass(MIR_OPTIMIZED, simplify::SimplifyCfg::new("elaborate-drops"));
295-
// No lifetime analysis based on borrowing can be done from here on out.
296-
297-
// From here on out, regions are gone.
298-
passes.push_pass(MIR_OPTIMIZED, erase_regions::EraseRegions);
299-
300-
// Optimizations begin.
301-
passes.push_pass(MIR_OPTIMIZED, inline::Inline);
302-
passes.push_pass(MIR_OPTIMIZED, instcombine::InstCombine);
303-
passes.push_pass(MIR_OPTIMIZED, deaggregator::Deaggregator);
304-
passes.push_pass(MIR_OPTIMIZED, copy_prop::CopyPropagation);
305-
passes.push_pass(MIR_OPTIMIZED, simplify::SimplifyLocals);
306-
307-
passes.push_pass(MIR_OPTIMIZED, generator::StateTransform);
308-
passes.push_pass(MIR_OPTIMIZED, add_call_guards::CriticalCallEdges);
309-
passes.push_pass(MIR_OPTIMIZED, dump_mir::Marker("PreTrans"));
310-
311-
for (index, pass) in passes.passes(suite).iter().enumerate() {
312-
let pass_num = MirPassIndex(index);
313-
314-
for hook in passes.hooks() {
315-
hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, false);
316-
}
317-
318-
pass.run_pass(tcx, source, mir);
319-
320-
for (index, promoted_mir) in mir.promoted.iter_enumerated_mut() {
321-
let promoted_source = MirSource::Promoted(source.item_id(), index);
322-
pass.run_pass(tcx, promoted_source, promoted_mir);
323-
324-
// Let's make sure we don't miss any nested instances
325-
assert!(promoted_mir.promoted.is_empty());
326-
}
198+
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
199+
// (Mir-)Borrowck uses `mir_validated`, so we have to force it to
200+
// execute before we can steal.
201+
let _ = tcx.mir_borrowck(def_id);
202+
let _ = tcx.borrowck(def_id);
327203

328-
for hook in passes.hooks() {
329-
hook.on_mir_pass(tcx, suite, pass_num, &pass.name(), source, &mir, true);
330-
}
331-
}
204+
let mut mir = tcx.mir_validated(def_id).steal();
205+
let source = MirSource::from_local_def_id(tcx, def_id);
206+
run_passes![tcx, mir, source, 2;
207+
no_landing_pads::NoLandingPads,
208+
simplify_branches::SimplifyBranches::new("initial"),
209+
210+
// These next passes must be executed together
211+
add_call_guards::CriticalCallEdges,
212+
elaborate_drops::ElaborateDrops,
213+
no_landing_pads::NoLandingPads,
214+
// AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
215+
// an AllCallEdges pass right before it.
216+
add_call_guards::AllCallEdges,
217+
add_validation::AddValidation,
218+
simplify::SimplifyCfg::new("elaborate-drops"),
219+
// No lifetime analysis based on borrowing can be done from here on out.
220+
221+
// From here on out, regions are gone.
222+
erase_regions::EraseRegions,
223+
224+
// Optimizations begin.
225+
inline::Inline,
226+
instcombine::InstCombine,
227+
deaggregator::Deaggregator,
228+
copy_prop::CopyPropagation,
229+
simplify::SimplifyLocals,
230+
231+
generator::StateTransform,
232+
add_call_guards::CriticalCallEdges,
233+
dump_mir::Marker("PreTrans"),
234+
];
235+
tcx.alloc_mir(mir)
332236
}

0 commit comments

Comments
 (0)