]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/transform.rs
rename `MirPassSet` to `MirSuite`
[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;
13 use hir::map::DefPathData;
14 use mir::{Mir, Promoted};
15 use ty::TyCtxt;
16 use std::cell::{Ref, RefCell};
17 use std::rc::Rc;
18 use syntax::ast::NodeId;
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 /// 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 suite(&self) -> MirSuite;
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 MirSuite(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).
120 pub trait PassHook {
121     fn on_mir_pass<'a, 'tcx: 'a>(&self,
122                                  mir_cx: &MirCtxt<'a, 'tcx>,
123                                  mir: Option<&Mir<'tcx>>);
124 }
125
126 /// A streamlined trait that you can implement to create a pass; the
127 /// pass will be invoked to process the MIR with the given `def_id`.
128 /// This lets you do things before we fetch the MIR itself.  You may
129 /// prefer `MirPass`.
130 pub trait DefIdPass {
131     fn name<'a>(&'a self) -> Cow<'a, str> {
132         default_name::<Self>()
133     }
134
135     fn run_pass<'a, 'tcx: 'a>(&self, mir_cx: &MirCtxt<'a, 'tcx>) -> &'tcx RefCell<Mir<'tcx>>;
136 }
137
138 /// A streamlined trait that you can implement to create a pass; the
139 /// pass will be named after the type, and it will consist of a main
140 /// loop that goes over each available MIR and applies `run_pass`.
141 pub trait MirPass: DepGraphSafe {
142     fn name<'a>(&'a self) -> Cow<'a, str> {
143         default_name::<Self>()
144     }
145
146     fn run_pass<'a, 'tcx>(&self,
147                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
148                           source: MirSource,
149                           mir: &mut Mir<'tcx>);
150 }
151
152 impl<T: MirPass> DefIdPass for T {
153     fn name<'a>(&'a self) -> Cow<'a, str> {
154         MirPass::name(self)
155     }
156
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
170     }
171 }
172
173 /// A manager for MIR passes.
174 #[derive(Clone)]
175 pub struct Passes {
176     pass_hooks: Vec<Rc<PassHook>>,
177     suites: Vec<Vec<Rc<DefIdPass>>>,
178 }
179
180 /// The number of "pass suites" that we have:
181 ///
182 /// - ready for constant evaluation
183 /// - unopt
184 /// - optimized
185 pub const MIR_SUITES: usize = 3;
186
187 /// Run the passes we need to do constant qualification and evaluation.
188 pub const MIR_CONST: MirSuite = MirSuite(0);
189
190 /// Run the passes we need to consider the MIR validated and ready for borrowck etc.
191 pub const MIR_VALIDATED: MirSuite = MirSuite(1);
192
193 /// Run the passes we need to consider the MIR *optimized*.
194 pub const MIR_OPTIMIZED: MirSuite = MirSuite(2);
195
196 impl<'a, 'tcx> Passes {
197     pub fn new() -> Passes {
198         Passes {
199             pass_hooks: Vec::new(),
200             suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(),
201         }
202     }
203
204     /// Pushes a built-in pass.
205     pub fn push_pass<T: DefIdPass + 'static>(&mut self, suite: MirSuite, pass: T) {
206         self.suites[suite.0].push(Rc::new(pass));
207     }
208
209     /// Pushes a pass hook.
210     pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
211         self.pass_hooks.push(Rc::new(hook));
212     }
213
214     pub fn len_passes(&self, suite: MirSuite) -> usize {
215         self.suites[suite.0].len()
216     }
217
218     pub fn pass(&self, suite: MirSuite, pass: MirPassIndex) -> &DefIdPass {
219         &*self.suites[suite.0][pass.0]
220     }
221
222     pub fn hooks(&self) -> &[Rc<PassHook>] {
223         &self.pass_hooks
224     }
225 }