]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/transform.rs
introduce `mir_keys()`
[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 dep_graph::DepNode;
12 use hir;
13 use hir::def_id::LOCAL_CRATE;
14 use hir::map::DefPathData;
15 use mir::{Mir, Promoted};
16 use ty::TyCtxt;
17 use syntax::ast::NodeId;
18 use util::common::time;
19
20 use std::borrow::Cow;
21 use std::fmt;
22
23 /// Where a specific Mir comes from.
24 #[derive(Debug, Copy, Clone)]
25 pub enum MirSource {
26     /// Functions and methods.
27     Fn(NodeId),
28
29     /// Constants and associated constants.
30     Const(NodeId),
31
32     /// Initializer of a `static` item.
33     Static(NodeId, hir::Mutability),
34
35     /// Promoted rvalues within a function.
36     Promoted(NodeId, Promoted)
37 }
38
39 impl<'a, 'tcx> MirSource {
40     pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
41         use hir::*;
42
43         // Handle constants in enum discriminants, types, and repeat expressions.
44         let def_id = tcx.hir.local_def_id(id);
45         let def_key = tcx.def_key(def_id);
46         if def_key.disambiguated_data.data == DefPathData::Initializer {
47             return MirSource::Const(id);
48         }
49
50         match tcx.hir.get(id) {
51             map::NodeItem(&Item { node: ItemConst(..), .. }) |
52             map::NodeTraitItem(&TraitItem { node: TraitItemKind::Const(..), .. }) |
53             map::NodeImplItem(&ImplItem { node: ImplItemKind::Const(..), .. }) => {
54                 MirSource::Const(id)
55             }
56             map::NodeItem(&Item { node: ItemStatic(_, m, _), .. }) => {
57                 MirSource::Static(id, m)
58             }
59             // Default to function if it's not a constant or static.
60             _ => MirSource::Fn(id)
61         }
62     }
63
64     pub fn item_id(&self) -> NodeId {
65         match *self {
66             MirSource::Fn(id) |
67             MirSource::Const(id) |
68             MirSource::Static(id, _) |
69             MirSource::Promoted(id, _) => id
70         }
71     }
72 }
73
74 /// Various information about pass.
75 pub trait Pass {
76     // fn should_run(Session) to check if pass should run?
77     fn name<'a>(&self) -> Cow<'static, str> {
78         let name = unsafe { ::std::intrinsics::type_name::<Self>() };
79         if let Some(tail) = name.rfind(":") {
80             Cow::from(&name[tail+1..])
81         } else {
82             Cow::from(name)
83         }
84     }
85     fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { None }
86 }
87
88 /// A pass which inspects the whole Mir map.
89 pub trait MirMapPass<'tcx>: Pass {
90     fn run_pass<'a>(
91         &mut self,
92         tcx: TyCtxt<'a, 'tcx, 'tcx>,
93         hooks: &mut [Box<for<'s> MirPassHook<'s>>]);
94 }
95
96 pub trait MirPassHook<'tcx>: Pass {
97     fn on_mir_pass<'a>(
98         &mut self,
99         tcx: TyCtxt<'a, 'tcx, 'tcx>,
100         src: MirSource,
101         mir: &Mir<'tcx>,
102         pass: &Pass,
103         is_after: bool
104     );
105 }
106
107 /// A pass which inspects Mir of functions in isolation.
108 pub trait MirPass<'tcx>: Pass {
109     fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
110                     src: MirSource, mir: &mut Mir<'tcx>);
111 }
112
113 impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
114     fn run_pass<'a>(&mut self,
115                     tcx: TyCtxt<'a, 'tcx, 'tcx>,
116                     hooks: &mut [Box<for<'s> MirPassHook<'s>>])
117     {
118         for &def_id in tcx.mir_keys(LOCAL_CRATE).iter() {
119             let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
120             let mir = &mut tcx.mir(def_id).borrow_mut();
121             tcx.dep_graph.write(DepNode::Mir(def_id));
122
123             let id = tcx.hir.as_local_node_id(def_id).unwrap();
124             let src = MirSource::from_node(tcx, id);
125
126             for hook in &mut *hooks {
127                 hook.on_mir_pass(tcx, src, mir, self, false);
128             }
129             MirPass::run_pass(self, tcx, src, mir);
130             for hook in &mut *hooks {
131                 hook.on_mir_pass(tcx, src, mir, self, true);
132             }
133
134             for (i, mir) in mir.promoted.iter_enumerated_mut() {
135                 let src = MirSource::Promoted(id, i);
136                 for hook in &mut *hooks {
137                     hook.on_mir_pass(tcx, src, mir, self, false);
138                 }
139                 MirPass::run_pass(self, tcx, src, mir);
140                 for hook in &mut *hooks {
141                     hook.on_mir_pass(tcx, src, mir, self, true);
142                 }
143             }
144         }
145     }
146 }
147
148 /// A manager for MIR passes.
149 pub struct Passes {
150     passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
151     pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
152     plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
153 }
154
155 impl<'a, 'tcx> Passes {
156     pub fn new() -> Passes {
157         let passes = Passes {
158             passes: Vec::new(),
159             pass_hooks: Vec::new(),
160             plugin_passes: Vec::new()
161         };
162         passes
163     }
164
165     pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
166         let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self;
167         for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) {
168             time(tcx.sess.time_passes(), &*pass.name(),
169                  || pass.run_pass(tcx, pass_hooks));
170         }
171     }
172
173     /// Pushes a built-in pass.
174     pub fn push_pass(&mut self, pass: Box<for<'b> MirMapPass<'b>>) {
175         self.passes.push(pass);
176     }
177
178     /// Pushes a pass hook.
179     pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
180         self.pass_hooks.push(hook);
181     }
182 }
183
184 /// Copies the plugin passes.
185 impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
186     fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
187         self.plugin_passes.extend(it);
188     }
189 }