Differences From
Artifact [9339be6648]:
4 4 //
5 5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 8 // option. This file may not be copied, modified, or distributed
9 9 // except according to those terms.
10 10
11 -use dep_graph::DepNode;
11 +//! See [the README](README.md) for details on writing your own pass.
12 +
12 13 use hir;
14 +use hir::def_id::DefId;
13 15 use hir::map::DefPathData;
14 16 use mir::{Mir, Promoted};
15 17 use ty::TyCtxt;
18 +use std::rc::Rc;
16 19 use syntax::ast::NodeId;
17 -use util::common::time;
18 20
19 21 use std::borrow::Cow;
20 -use std::fmt;
21 22
22 23 /// Where a specific Mir comes from.
23 24 #[derive(Debug, Copy, Clone)]
24 25 pub enum MirSource {
25 26 /// Functions and methods.
26 27 Fn(NodeId),
27 28
................................................................................
32 33 Static(NodeId, hir::Mutability),
33 34
34 35 /// Promoted rvalues within a function.
35 36 Promoted(NodeId, Promoted)
36 37 }
37 38
38 39 impl<'a, 'tcx> MirSource {
40 + pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource {
41 + let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
42 + Self::from_node(tcx, id)
43 + }
44 +
39 45 pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
40 46 use hir::*;
41 47
42 48 // Handle constants in enum discriminants, types, and repeat expressions.
43 49 let def_id = tcx.hir.local_def_id(id);
44 50 let def_key = tcx.def_key(def_id);
45 51 if def_key.disambiguated_data.data == DefPathData::Initializer {
................................................................................
66 72 MirSource::Const(id) |
67 73 MirSource::Static(id, _) |
68 74 MirSource::Promoted(id, _) => id
69 75 }
70 76 }
71 77 }
72 78
73 -/// Various information about pass.
74 -pub trait Pass {
75 - // fn should_run(Session) to check if pass should run?
76 - fn name<'a>(&self) -> Cow<'static, str> {
77 - let name = unsafe { ::std::intrinsics::type_name::<Self>() };
78 - if let Some(tail) = name.rfind(":") {
79 - Cow::from(&name[tail+1..])
80 - } else {
81 - Cow::from(name)
82 - }
79 +/// Generates a default name for the pass based on the name of the
80 +/// type `T`.
81 +pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
82 + let name = unsafe { ::std::intrinsics::type_name::<T>() };
83 + if let Some(tail) = name.rfind(":") {
84 + Cow::from(&name[tail+1..])
85 + } else {
86 + Cow::from(name)
83 87 }
84 - fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { None }
85 88 }
86 89
87 -/// A pass which inspects the whole Mir map.
88 -pub trait MirMapPass<'tcx>: Pass {
89 - fn run_pass<'a>(
90 - &mut self,
91 - tcx: TyCtxt<'a, 'tcx, 'tcx>,
92 - hooks: &mut [Box<for<'s> MirPassHook<'s>>]);
93 -}
94 -
95 -pub trait MirPassHook<'tcx>: Pass {
96 - fn on_mir_pass<'a>(
97 - &mut self,
98 - tcx: TyCtxt<'a, 'tcx, 'tcx>,
99 - src: MirSource,
100 - mir: &Mir<'tcx>,
101 - pass: &Pass,
102 - is_after: bool
103 - );
104 -}
105 -
106 -/// A pass which inspects Mir of functions in isolation.
107 -pub trait MirPass<'tcx>: Pass {
108 - fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
109 - src: MirSource, mir: &mut Mir<'tcx>);
90 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
91 +pub struct MirSuite(pub usize);
92 +
93 +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
94 +pub struct MirPassIndex(pub usize);
95 +
96 +/// A pass hook is invoked both before and after each pass executes.
97 +/// This is primarily used to dump MIR for debugging.
98 +///
99 +/// You can tell whether this is before or after by inspecting the
100 +/// `mir` parameter -- before the pass executes, it will be `None` (in
101 +/// which case you can inspect the MIR from previous pass by executing
102 +/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
103 +/// `Some()` with the result of the pass (in which case the output
104 +/// from the previous pass is most likely stolen, so you would not
105 +/// want to try and access it). If the pass is interprocedural, then
106 +/// the hook will be invoked once per output.
107 +pub trait PassHook {
108 + fn on_mir_pass<'a, 'tcx: 'a>(&self,
109 + tcx: TyCtxt<'a, 'tcx, 'tcx>,
110 + suite: MirSuite,
111 + pass_num: MirPassIndex,
112 + pass_name: &str,
113 + source: MirSource,
114 + mir: &Mir<'tcx>,
115 + is_after: bool);
110 116 }
111 117
112 -impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
113 - fn run_pass<'a>(&mut self,
114 - tcx: TyCtxt<'a, 'tcx, 'tcx>,
115 - hooks: &mut [Box<for<'s> MirPassHook<'s>>])
116 - {
117 - let def_ids = tcx.maps.mir.borrow().keys();
118 - for def_id in def_ids {
119 - if !def_id.is_local() {
120 - continue;
121 - }
118 +/// The full suite of types that identifies a particular
119 +/// application of a pass to a def-id.
120 +pub type PassId = (MirSuite, MirPassIndex, DefId);
122 121
123 - let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
124 - let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
125 - tcx.dep_graph.write(DepNode::Mir(def_id));
122 +/// A streamlined trait that you can implement to create a pass; the
123 +/// pass will be named after the type, and it will consist of a main
124 +/// loop that goes over each available MIR and applies `run_pass`.
125 +pub trait MirPass {
126 + fn name<'a>(&'a self) -> Cow<'a, str> {
127 + default_name::<Self>()
128 + }
126 129
127 - let id = tcx.hir.as_local_node_id(def_id).unwrap();
128 - let src = MirSource::from_node(tcx, id);
129 -
130 - for hook in &mut *hooks {
131 - hook.on_mir_pass(tcx, src, mir, self, false);
132 - }
133 - MirPass::run_pass(self, tcx, src, mir);
134 - for hook in &mut *hooks {
135 - hook.on_mir_pass(tcx, src, mir, self, true);
136 - }
137 -
138 - for (i, mir) in mir.promoted.iter_enumerated_mut() {
139 - let src = MirSource::Promoted(id, i);
140 - for hook in &mut *hooks {
141 - hook.on_mir_pass(tcx, src, mir, self, false);
142 - }
143 - MirPass::run_pass(self, tcx, src, mir);
144 - for hook in &mut *hooks {
145 - hook.on_mir_pass(tcx, src, mir, self, true);
146 - }
147 - }
148 - }
149 - }
130 + fn run_pass<'a, 'tcx>(&self,
131 + tcx: TyCtxt<'a, 'tcx, 'tcx>,
132 + source: MirSource,
133 + mir: &mut Mir<'tcx>);
150 134 }
151 135
152 136 /// A manager for MIR passes.
137 +///
138 +/// FIXME(#41712) -- it is unclear whether we should have this struct.
139 +#[derive(Clone)]
153 140 pub struct Passes {
154 - passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
155 - pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
156 - plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
141 + pass_hooks: Vec<Rc<PassHook>>,
142 + suites: Vec<Vec<Rc<MirPass>>>,
157 143 }
158 144
145 +/// The number of "pass suites" that we have:
146 +///
147 +/// - ready for constant evaluation
148 +/// - unopt
149 +/// - optimized
150 +pub const MIR_SUITES: usize = 3;
151 +
152 +/// Run the passes we need to do constant qualification and evaluation.
153 +pub const MIR_CONST: MirSuite = MirSuite(0);
154 +
155 +/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
156 +pub const MIR_VALIDATED: MirSuite = MirSuite(1);
157 +
158 +/// Run the passes we need to consider the MIR *optimized*.
159 +pub const MIR_OPTIMIZED: MirSuite = MirSuite(2);
160 +
159 161 impl<'a, 'tcx> Passes {
160 162 pub fn new() -> Passes {
161 - let passes = Passes {
162 - passes: Vec::new(),
163 + Passes {
163 164 pass_hooks: Vec::new(),
164 - plugin_passes: Vec::new()
165 - };
166 - passes
167 - }
168 -
169 - pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
170 - let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self;
171 - for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) {
172 - time(tcx.sess.time_passes(), &*pass.name(),
173 - || pass.run_pass(tcx, pass_hooks));
165 + suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(),
174 166 }
175 167 }
176 168
177 169 /// Pushes a built-in pass.
178 - pub fn push_pass(&mut self, pass: Box<for<'b> MirMapPass<'b>>) {
179 - self.passes.push(pass);
170 + pub fn push_pass<T: MirPass + 'static>(&mut self, suite: MirSuite, pass: T) {
171 + self.suites[suite.0].push(Rc::new(pass));
180 172 }
181 173
182 174 /// Pushes a pass hook.
183 - pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
184 - self.pass_hooks.push(hook);
175 + pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
176 + self.pass_hooks.push(Rc::new(hook));
185 177 }
186 -}
178 +
179 + pub fn passes(&self, suite: MirSuite) -> &[Rc<MirPass>] {
180 + &self.suites[suite.0]
181 + }
187 182
188 -/// Copies the plugin passes.
189 -impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
190 - fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
191 - self.plugin_passes.extend(it);
183 + pub fn hooks(&self) -> &[Rc<PassHook>] {
184 + &self.pass_hooks
192 185 }
193 186 }