]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/transform.rs
8ecfbfdb5c3ef35ab8f41d62979b43d9c81fe679
[rust.git] / src / librustc / mir / transform.rs
1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use hir;
12 use hir::def_id::{DefId, LOCAL_CRATE};
13 use hir::map::DefPathData;
14 use mir::{Mir, Promoted};
15 use ty::TyCtxt;
16 use std::rc::Rc;
17 use syntax::ast::NodeId;
18 use util::common::time;
19
20 use std::borrow::Cow;
21
22 /// Where a specific Mir comes from.
23 #[derive(Debug, Copy, Clone)]
24 pub enum MirSource {
25     /// Functions and methods.
26     Fn(NodeId),
27
28     /// Constants and associated constants.
29     Const(NodeId),
30
31     /// Initializer of a `static` item.
32     Static(NodeId, hir::Mutability),
33
34     /// Promoted rvalues within a function.
35     Promoted(NodeId, Promoted)
36 }
37
38 impl<'a, 'tcx> MirSource {
39     pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
40         use hir::*;
41
42         // Handle constants in enum discriminants, types, and repeat expressions.
43         let def_id = tcx.hir.local_def_id(id);
44         let def_key = tcx.def_key(def_id);
45         if def_key.disambiguated_data.data == DefPathData::Initializer {
46             return MirSource::Const(id);
47         }
48
49         match tcx.hir.get(id) {
50             map::NodeItem(&Item { node: ItemConst(..), .. }) |
51             map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
52             map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
53                 MirSource::Const(id)
54             }
55             map::NodeItem(&Item { node: ItemStatic(_, m, _), .. }) => {
56                 MirSource::Static(id, m)
57             }
58             // Default to function if it's not a constant or static.
59             _ => MirSource::Fn(id)
60         }
61     }
62
63     pub fn item_id(&self) -> NodeId {
64         match *self {
65             MirSource::Fn(id) |
66             MirSource::Const(id) |
67             MirSource::Static(id, _) |
68             MirSource::Promoted(id, _) => id
69         }
70     }
71 }
72
73 /// Various information about pass.
74 pub trait Pass {
75     fn name<'a>(&'a self) -> Cow<'a, str> {
76         default_name::<Self>()
77     }
78
79     fn run_pass<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>);
80 }
81
82 /// Generates a default name for the pass based on the name of the
83 /// type `T`.
84 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
85     let name = unsafe { ::std::intrinsics::type_name::<T>() };
86     if let Some(tail) = name.rfind(":") {
87         Cow::from(&name[tail+1..])
88     } else {
89         Cow::from(name)
90     }
91 }
92
93 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);
99 }
100
101 /// A streamlined trait that you can implement to create a pass; the
102 /// pass will be invoked to process the MIR with the given `def_id`.
103 /// This lets you do things before we fetch the MIR itself.  You may
104 /// prefer `MirPass`.
105 pub trait DefIdPass {
106     fn name<'a>(&'a self) -> Cow<'a, str> {
107         default_name::<Self>()
108     }
109
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     }
125 }
126
127 /// A streamlined trait that you can implement to create a pass; the
128 /// pass will be named after the type, and it will consist of a main
129 /// loop that goes over each available MIR and applies `run_pass`.
130 pub trait MirPass: DepGraphSafe {
131     fn name<'a>(&'a self) -> Cow<'a, str> {
132         default_name::<Self>()
133     }
134
135     fn run_pass<'a, 'tcx>(&self,
136                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
137                           source: MirSource,
138                           mir: &mut Mir<'tcx>);
139 }
140
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
157 impl<T: MirPass> DefIdPass for T {
158     fn name<'a>(&'a self) -> Cow<'a, str> {
159         MirPass::name(self)
160     }
161
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));
164     }
165 }
166
167 /// A manager for MIR passes.
168 #[derive(Clone)]
169 pub struct Passes {
170     pass_hooks: Vec<Rc<PassHook>>,
171     sets: Vec<PassSet>,
172 }
173
174 #[derive(Clone)]
175 struct PassSet {
176     passes: Vec<Rc<DefIdPass>>,
177 }
178
179 /// The number of "pass sets" that we have:
180 ///
181 /// - ready for constant evaluation
182 /// - unopt
183 /// - optimized
184 pub const MIR_PASS_SETS: usize = 3;
185
186 /// Run the passes we need to do constant qualification and evaluation.
187 pub const MIR_CONST: usize = 0;
188
189 /// Run the passes we need to consider the MIR validated and ready for borrowck etc.
190 pub const MIR_VALIDATED: usize = 1;
191
192 /// Run the passes we need to consider the MIR *optimized*.
193 pub const MIR_OPTIMIZED: usize = 2;
194
195 impl<'a, 'tcx> Passes {
196     pub fn new() -> Passes {
197         Passes {
198             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             }
223         }
224     }
225
226     /// 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));
229     }
230
231     /// Pushes a pass hook.
232     pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
233         self.pass_hooks.push(Rc::new(hook));
234     }
235 }