]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/mod.rs
Use `Body` everywhere
[rust.git] / src / librustc_mir / transform / mod.rs
1 use crate::{shim, util};
2 use rustc_ast::ast;
3 use rustc_hir as hir;
4 use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, LocalDefId, LOCAL_CRATE};
5 use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
6 use rustc_index::vec::IndexVec;
7 use rustc_middle::mir::{Body, ConstQualifs, MirPhase, Promoted};
8 use rustc_middle::ty::query::Providers;
9 use rustc_middle::ty::steal::Steal;
10 use rustc_middle::ty::{InstanceDef, TyCtxt, TypeFoldable};
11 use rustc_span::Span;
12 use std::borrow::Cow;
13
14 pub mod add_call_guards;
15 pub mod add_moves_for_packed_drops;
16 pub mod add_retag;
17 pub mod check_consts;
18 pub mod check_unsafety;
19 pub mod cleanup_post_borrowck;
20 pub mod const_prop;
21 pub mod copy_prop;
22 pub mod deaggregator;
23 pub mod dump_mir;
24 pub mod elaborate_drops;
25 pub mod generator;
26 pub mod inline;
27 pub mod instcombine;
28 pub mod no_landing_pads;
29 pub mod promote_consts;
30 pub mod qualify_min_const_fn;
31 pub mod remove_noop_landing_pads;
32 pub mod rustc_peek;
33 pub mod simplify;
34 pub mod simplify_branches;
35 pub mod simplify_try;
36 pub mod uninhabited_enum_branching;
37 pub mod unreachable_prop;
38
39 pub(crate) fn provide(providers: &mut Providers<'_>) {
40     self::check_unsafety::provide(providers);
41     *providers = Providers {
42         mir_keys,
43         mir_const,
44         mir_const_qualif,
45         mir_validated,
46         optimized_mir,
47         is_mir_available,
48         promoted_mir,
49         ..*providers
50     };
51 }
52
53 fn is_mir_available(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
54     tcx.mir_keys(def_id.krate).contains(&def_id)
55 }
56
57 /// Finds the full set of `DefId`s within the current crate that have
58 /// MIR associated with them.
59 fn mir_keys(tcx: TyCtxt<'_>, krate: CrateNum) -> &DefIdSet {
60     assert_eq!(krate, LOCAL_CRATE);
61
62     let mut set = DefIdSet::default();
63
64     // All body-owners have MIR associated with them.
65     set.extend(tcx.body_owners().map(LocalDefId::to_def_id));
66
67     // Additionally, tuple struct/variant constructors have MIR, but
68     // they don't have a BodyId, so we need to build them separately.
69     struct GatherCtors<'a, 'tcx> {
70         tcx: TyCtxt<'tcx>,
71         set: &'a mut DefIdSet,
72     }
73     impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
74         fn visit_variant_data(
75             &mut self,
76             v: &'tcx hir::VariantData<'tcx>,
77             _: ast::Name,
78             _: &'tcx hir::Generics<'tcx>,
79             _: hir::HirId,
80             _: Span,
81         ) {
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         type Map = intravisit::ErasedMap<'tcx>;
88         fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
89             NestedVisitorMap::None
90         }
91     }
92     tcx.hir()
93         .krate()
94         .visit_all_item_likes(&mut GatherCtors { tcx, set: &mut set }.as_deep_visitor());
95
96     tcx.arena.alloc(set)
97 }
98
99 /// Where a specific `mir::Body` comes from.
100 #[derive(Debug, Copy, Clone)]
101 pub struct MirSource<'tcx> {
102     pub instance: InstanceDef<'tcx>,
103
104     /// If `Some`, this is a promoted rvalue within the parent function.
105     pub promoted: Option<Promoted>,
106 }
107
108 impl<'tcx> MirSource<'tcx> {
109     pub fn item(def_id: DefId) -> Self {
110         MirSource { instance: InstanceDef::Item(def_id), promoted: None }
111     }
112
113     #[inline]
114     pub fn def_id(&self) -> DefId {
115         self.instance.def_id()
116     }
117 }
118
119 /// Generates a default name for the pass based on the name of the
120 /// type `T`.
121 pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
122     let name = ::std::any::type_name::<T>();
123     if let Some(tail) = name.rfind(':') { Cow::from(&name[tail + 1..]) } else { Cow::from(name) }
124 }
125
126 /// A streamlined trait that you can implement to create a pass; the
127 /// pass will be named after the type, and it will consist of a main
128 /// loop that goes over each available MIR and applies `run_pass`.
129 pub trait MirPass<'tcx> {
130     fn name(&self) -> Cow<'_, str> {
131         default_name::<Self>()
132     }
133
134     fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>);
135 }
136
137 pub fn run_passes(
138     tcx: TyCtxt<'tcx>,
139     body: &mut Body<'tcx>,
140     instance: InstanceDef<'tcx>,
141     promoted: Option<Promoted>,
142     mir_phase: MirPhase,
143     passes: &[&dyn MirPass<'tcx>],
144 ) {
145     let phase_index = mir_phase.phase_index();
146
147     if body.phase >= mir_phase {
148         return;
149     }
150
151     let source = MirSource { instance, promoted };
152     let mut index = 0;
153     let mut run_pass = |pass: &dyn MirPass<'tcx>| {
154         let run_hooks = |body: &_, index, is_after| {
155             dump_mir::on_mir_pass(
156                 tcx,
157                 &format_args!("{:03}-{:03}", phase_index, index),
158                 &pass.name(),
159                 source,
160                 body,
161                 is_after,
162             );
163         };
164         run_hooks(body, index, false);
165         pass.run_pass(tcx, source, body);
166         run_hooks(body, index, true);
167
168         index += 1;
169     };
170
171     for pass in passes {
172         run_pass(*pass);
173     }
174
175     body.phase = mir_phase;
176 }
177
178 fn mir_const_qualif(tcx: TyCtxt<'_>, def_id: DefId) -> ConstQualifs {
179     let const_kind = check_consts::ConstKind::for_item(tcx, def_id);
180
181     // No need to const-check a non-const `fn`.
182     if const_kind.is_none() {
183         return Default::default();
184     }
185
186     // N.B., this `borrow()` is guaranteed to be valid (i.e., the value
187     // cannot yet be stolen), because `mir_validated()`, which steals
188     // from `mir_const(), forces this query to execute before
189     // performing the steal.
190     let body = &tcx.mir_const(def_id).borrow();
191
192     if body.return_ty().references_error() {
193         tcx.sess.delay_span_bug(body.span, "mir_const_qualif: MIR had errors");
194         return Default::default();
195     }
196
197     let item =
198         check_consts::Item { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) };
199
200     let mut validator = check_consts::validation::Validator::new(&item);
201     validator.check_body();
202
203     // We return the qualifs in the return place for every MIR body, even though it is only used
204     // when deciding to promote a reference to a `const` for now.
205     validator.qualifs_in_return_place()
206 }
207
208 fn mir_const(tcx: TyCtxt<'_>, def_id: DefId) -> &Steal<Body<'_>> {
209     // Unsafety check uses the raw mir, so make sure it is run
210     let _ = tcx.unsafety_check_result(def_id);
211
212     let mut body = tcx.mir_built(def_id).steal();
213
214     util::dump_mir(tcx, None, "mir_map", &0, MirSource::item(def_id), &body, |_, _| Ok(()));
215
216     run_passes(
217         tcx,
218         &mut body,
219         InstanceDef::Item(def_id),
220         None,
221         MirPhase::Const,
222         &[
223             // What we need to do constant evaluation.
224             &simplify::SimplifyCfg::new("initial"),
225             &rustc_peek::SanityCheck,
226         ],
227     );
228     tcx.alloc_steal_mir(body)
229 }
230
231 fn mir_validated(
232     tcx: TyCtxt<'tcx>,
233     def_id: DefId,
234 ) -> (&'tcx Steal<Body<'tcx>>, &'tcx Steal<IndexVec<Promoted, Body<'tcx>>>) {
235     // Ensure that we compute the `mir_const_qualif` for constants at
236     // this point, before we steal the mir-const result.
237     let _ = tcx.mir_const_qualif(def_id);
238
239     let mut body = tcx.mir_const(def_id).steal();
240     let promote_pass = promote_consts::PromoteTemps::default();
241     run_passes(
242         tcx,
243         &mut body,
244         InstanceDef::Item(def_id),
245         None,
246         MirPhase::Validated,
247         &[
248             // What we need to run borrowck etc.
249             &promote_pass,
250             &simplify::SimplifyCfg::new("qualify-consts"),
251         ],
252     );
253
254     let promoted = promote_pass.promoted_fragments.into_inner();
255     (tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
256 }
257
258 fn run_optimization_passes<'tcx>(
259     tcx: TyCtxt<'tcx>,
260     body: &mut Body<'tcx>,
261     def_id: DefId,
262     promoted: Option<Promoted>,
263 ) {
264     run_passes(
265         tcx,
266         body,
267         InstanceDef::Item(def_id),
268         promoted,
269         MirPhase::Optimized,
270         &[
271             // Remove all things only needed by analysis
272             &no_landing_pads::NoLandingPads::new(tcx),
273             &simplify_branches::SimplifyBranches::new("initial"),
274             &remove_noop_landing_pads::RemoveNoopLandingPads,
275             &cleanup_post_borrowck::CleanupNonCodegenStatements,
276             &simplify::SimplifyCfg::new("early-opt"),
277             // These next passes must be executed together
278             &add_call_guards::CriticalCallEdges,
279             &elaborate_drops::ElaborateDrops,
280             &no_landing_pads::NoLandingPads::new(tcx),
281             // AddMovesForPackedDrops needs to run after drop
282             // elaboration.
283             &add_moves_for_packed_drops::AddMovesForPackedDrops,
284             // `AddRetag` needs to run after `ElaborateDrops`. Otherwise it should run fairly late,
285             // but before optimizations begin.
286             &add_retag::AddRetag,
287             &simplify::SimplifyCfg::new("elaborate-drops"),
288             // No lifetime analysis based on borrowing can be done from here on out.
289
290             // Optimizations begin.
291             &unreachable_prop::UnreachablePropagation,
292             &uninhabited_enum_branching::UninhabitedEnumBranching,
293             &simplify::SimplifyCfg::new("after-uninhabited-enum-branching"),
294             &inline::Inline,
295             // Lowering generator control-flow and variables
296             // has to happen before we do anything else to them.
297             &generator::StateTransform,
298             &instcombine::InstCombine,
299             &const_prop::ConstProp,
300             &simplify_branches::SimplifyBranches::new("after-const-prop"),
301             &deaggregator::Deaggregator,
302             &copy_prop::CopyPropagation,
303             &simplify_branches::SimplifyBranches::new("after-copy-prop"),
304             &remove_noop_landing_pads::RemoveNoopLandingPads,
305             &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"),
306             &simplify_try::SimplifyArmIdentity,
307             &simplify_try::SimplifyBranchSame,
308             &simplify::SimplifyCfg::new("final"),
309             &simplify::SimplifyLocals,
310             &add_call_guards::CriticalCallEdges,
311             &dump_mir::Marker("PreCodegen"),
312         ],
313     );
314 }
315
316 fn optimized_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &Body<'_> {
317     if tcx.is_constructor(def_id) {
318         // There's no reason to run all of the MIR passes on constructors when
319         // we can just output the MIR we want directly. This also saves const
320         // qualification and borrow checking the trouble of special casing
321         // constructors.
322         return shim::build_adt_ctor(tcx, def_id);
323     }
324
325     // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
326     // execute before we can steal.
327     tcx.ensure().mir_borrowck(def_id);
328
329     let (body, _) = tcx.mir_validated(def_id);
330     let mut body = body.steal();
331     run_optimization_passes(tcx, &mut body, def_id, None);
332
333     debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");
334
335     tcx.arena.alloc(body)
336 }
337
338 fn promoted_mir(tcx: TyCtxt<'_>, def_id: DefId) -> &IndexVec<Promoted, Body<'_>> {
339     if tcx.is_constructor(def_id) {
340         return tcx.intern_promoted(IndexVec::new());
341     }
342
343     tcx.ensure().mir_borrowck(def_id);
344     let (_, promoted) = tcx.mir_validated(def_id);
345     let mut promoted = promoted.steal();
346
347     for (p, mut body) in promoted.iter_enumerated_mut() {
348         run_optimization_passes(tcx, &mut body, def_id, Some(p));
349     }
350
351     debug_assert!(!promoted.has_free_regions(), "Free regions in promoted MIR");
352
353     tcx.intern_promoted(promoted)
354 }