]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/transform/mod.rs
New upstream version 1.40.0+dfsg1
[rustc.git] / src / librustc_mir / transform / mod.rs
1 use crate::{build, shim};
2 use rustc_index::vec::IndexVec;
3 use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
4 use rustc::mir::{Body, MirPhase, Promoted};
5 use rustc::ty::{TyCtxt, InstanceDef};
6 use rustc::ty::query::Providers;
7 use rustc::ty::steal::Steal;
8 use rustc::hir;
9 use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
10 use rustc::util::nodemap::DefIdSet;
11 use std::borrow::Cow;
12 use syntax::ast;
13 use syntax_pos::Span;
14
15 pub mod add_retag;
16 pub mod add_moves_for_packed_drops;
17 pub mod cleanup_post_borrowck;
18 pub mod check_consts;
19 pub mod check_unsafety;
20 pub mod simplify_branches;
21 pub mod simplify;
22 pub mod erase_regions;
23 pub mod no_landing_pads;
24 pub mod rustc_peek;
25 pub mod elaborate_drops;
26 pub mod add_call_guards;
27 pub mod promote_consts;
28 pub mod qualify_consts;
29 pub mod qualify_min_const_fn;
30 pub mod remove_noop_landing_pads;
31 pub mod dump_mir;
32 pub mod deaggregator;
33 pub mod instcombine;
34 pub mod copy_prop;
35 pub mod const_prop;
36 pub mod generator;
37 pub mod inline;
38 pub mod uniform_array_move_out;
39
40 pub(crate) fn provide(providers: &mut Providers<'_>) {
41 self::qualify_consts::provide(providers);
42 self::check_unsafety::provide(providers);
43 *providers = Providers {
44 mir_keys,
45 mir_built,
46 mir_const,
47 mir_validated,
48 optimized_mir,
49 is_mir_available,
50 promoted_mir,
51 ..*providers
52 };
53 }
54
55 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
56 tcx.mir_keys(def_id.krate).contains(&def_id)
57 }
58
59 /// Finds the full set of `DefId`s within the current crate that have
60 /// MIR associated with them.
61 fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> &DefIdSet {
62 assert_eq!(krate, LOCAL_CRATE);
63
64 let mut set = DefIdSet::default();
65
66 // All body-owners have MIR associated with them.
67 set.extend(tcx.body_owners());
68
69 // Additionally, tuple struct/variant constructors have MIR, but
70 // they don't have a BodyId, so we need to build them separately.
71 struct GatherCtors<'a, 'tcx> {
72 tcx: TyCtxt<'tcx>,
73 set: &'a mut DefIdSet,
74 }
75 impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
76 fn visit_variant_data(&mut self,
77 v: &'tcx hir::VariantData,
78 _: ast::Name,
79 _: &'tcx hir::Generics,
80 _: hir::HirId,
81 _: Span) {
82 if let hir::VariantData::Tuple(_, hir_id) = *v {
83 self.set.insert(self.tcx.hir().local_def_id(hir_id));
84 }
85 intravisit::walk_struct_def(self, v)
86 }
87 fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
88 NestedVisitorMap::None
89 }
90 }
91 tcx.hir().krate().visit_all_item_likes(&mut GatherCtors {
92 tcx,
93 set: &mut set,
94 }.as_deep_visitor());
95
96 tcx.arena.alloc(set)
97 }
98
99 fn mir_built(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
100 let mir = build::mir_build(tcx, def_id);
101 tcx.alloc_steal_mir(mir)
102 }
103
104 /// Where a specific `mir::Body` comes from.
105 #[derive(Debug, Copy, Clone)]
106 pub struct MirSource<'tcx> {
107 pub instance: InstanceDef<'tcx>,
108
109 /// If `Some`, this is a promoted rvalue within the parent function.
110 pub promoted: Option<Promoted>,
111 }
112
113 impl<'tcx> MirSource<'tcx> {
114 pub fn item(def_id: DefId) -> Self {
115 MirSource {
116 instance: InstanceDef::Item(def_id),
117 promoted: None
118 }
119 }
120
121 #[inline]
122 pub fn def_id(&self) -> DefId {
123 self.instance.def_id()
124 }
125 }
126
127 /// Generates a default name for the pass based on the name of the
128 /// type `T`.
129 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
130 let name = ::std::any::type_name::<T>();
131 if let Some(tail) = name.rfind(":") {
132 Cow::from(&name[tail+1..])
133 } else {
134 Cow::from(name)
135 }
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<'tcx> {
142 fn name(&self) -> Cow<'_, str> {
143 default_name::<Self>()
144 }
145
146 fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>);
147 }
148
149 pub fn run_passes(
150 tcx: TyCtxt<'tcx>,
151 body: &mut Body<'tcx>,
152 instance: InstanceDef<'tcx>,
153 promoted: Option<Promoted>,
154 mir_phase: MirPhase,
155 passes: &[&dyn MirPass<'tcx>],
156 ) {
157 let phase_index = mir_phase.phase_index();
158
159 if body.phase >= mir_phase {
160 return;
161 }
162
163 let source = MirSource {
164 instance,
165 promoted,
166 };
167 let mut index = 0;
168 let mut run_pass = |pass: &dyn MirPass<'tcx>| {
169 let run_hooks = |body: &_, index, is_after| {
170 dump_mir::on_mir_pass(tcx, &format_args!("{:03}-{:03}", phase_index, index),
171 &pass.name(), source, body, is_after);
172 };
173 run_hooks(body, index, false);
174 pass.run_pass(tcx, source, body);
175 run_hooks(body, index, true);
176
177 index += 1;
178 };
179
180 for pass in passes {
181 run_pass(*pass);
182 }
183
184 body.phase = mir_phase;
185 }
186
187 fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
188 // Unsafety check uses the raw mir, so make sure it is run
189 let _ = tcx.unsafety_check_result(def_id);
190
191 let mut body = tcx.mir_built(def_id).steal();
192 run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Const, &[
193 // What we need to do constant evaluation.
194 &simplify::SimplifyCfg::new("initial"),
195 &rustc_peek::SanityCheck,
196 &uniform_array_move_out::UniformArrayMoveOut,
197 ]);
198 tcx.alloc_steal_mir(body)
199 }
200
201 fn mir_validated(
202 tcx: TyCtxt<'tcx>,
203 def_id: DefId,
204 ) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
205 let hir_id = tcx.hir().as_local_hir_id(def_id).unwrap();
206 if let hir::BodyOwnerKind::Const = tcx.hir().body_owner_kind(hir_id) {
207 // Ensure that we compute the `mir_const_qualif` for constants at
208 // this point, before we steal the mir-const result.
209 let _ = tcx.mir_const_qualif(def_id);
210 }
211
212 let mut body = tcx.mir_const(def_id).steal();
213 let qualify_and_promote_pass = qualify_consts::QualifyAndPromoteConstants::default();
214 run_passes(tcx, &mut body, InstanceDef::Item(def_id), None, MirPhase::Validated, &[
215 // What we need to run borrowck etc.
216 &qualify_and_promote_pass,
217 &simplify::SimplifyCfg::new("qualify-consts"),
218 ]);
219 let promoted = qualify_and_promote_pass.promoted.into_inner();
220 (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
221 }
222
223 fn run_optimization_passes<'tcx>(
224 tcx: TyCtxt<'tcx>,
225 body: &mut Body<'tcx>,
226 def_id: DefId,
227 promoted: Option<Promoted>,
228 ) {
229 run_passes(tcx, body, InstanceDef::Item(def_id), promoted, MirPhase::Optimized, &[
230 // Remove all things only needed by analysis
231 &no_landing_pads::NoLandingPads::new(tcx),
232 &simplify_branches::SimplifyBranches::new("initial"),
233 &remove_noop_landing_pads::RemoveNoopLandingPads,
234 &cleanup_post_borrowck::CleanupNonCodegenStatements,
235
236 &simplify::SimplifyCfg::new("early-opt"),
237
238 // These next passes must be executed together
239 &add_call_guards::CriticalCallEdges,
240 &elaborate_drops::ElaborateDrops,
241 &no_landing_pads::NoLandingPads::new(tcx),
242 // AddMovesForPackedDrops needs to run after drop
243 // elaboration.
244 &add_moves_for_packed_drops::AddMovesForPackedDrops,
245 // AddRetag needs to run after ElaborateDrops, and it needs
246 // an AllCallEdges pass right before it. Otherwise it should
247 // run fairly late, but before optimizations begin.
248 &add_call_guards::AllCallEdges,
249 &add_retag::AddRetag,
250
251 &simplify::SimplifyCfg::new("elaborate-drops"),
252
253 // No lifetime analysis based on borrowing can be done from here on out.
254
255 // From here on out, regions are gone.
256 &erase_regions::EraseRegions,
257
258
259 // Optimizations begin.
260 &uniform_array_move_out::RestoreSubsliceArrayMoveOut::new(tcx),
261 &inline::Inline,
262
263 // Lowering generator control-flow and variables
264 // has to happen before we do anything else to them.
265 &generator::StateTransform,
266
267 &instcombine::InstCombine,
268 &const_prop::ConstProp,
269 &simplify_branches::SimplifyBranches::new("after-const-prop"),
270 &deaggregator::Deaggregator,
271 &copy_prop::CopyPropagation,
272 &simplify_branches::SimplifyBranches::new("after-copy-prop"),
273 &remove_noop_landing_pads::RemoveNoopLandingPads,
274 &simplify::SimplifyCfg::new("final"),
275 &simplify::SimplifyLocals,
276
277 &add_call_guards::CriticalCallEdges,
278 &dump_mir::Marker("PreCodegen"),
279 ]);
280 }
281
282 fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
283 if tcx.is_constructor(def_id) {
284 // There's no reason to run all of the MIR passes on constructors when
285 // we can just output the MIR we want directly. This also saves const
286 // qualification and borrow checking the trouble of special casing
287 // constructors.
288 return shim::build_adt_ctor(tcx, def_id);
289 }
290
291 // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
292 // execute before we can steal.
293 tcx.ensure().mir_borrowck(def_id);
294
295 let (body, _) = tcx.mir_validated(def_id);
296 let mut body = body.steal();
297 run_optimization_passes(tcx, &mut body, def_id, None);
298 tcx.arena.alloc(body)
299 }
300
301 fn promoted_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
302 if tcx.is_constructor(def_id) {
303 return tcx.intern_promoted(IndexVec::new());
304 }
305
306 tcx.ensure().mir_borrowck(def_id);
307 let (_, promoted) = tcx.mir_validated(def_id);
308 let mut promoted = promoted.steal();
309
310 for (p, mut body) in promoted.iter_enumerated_mut() {
311 run_optimization_passes(tcx, &mut body, def_id, Some(p));
312 }
313
314 tcx.intern_promoted(promoted)
315 }