mod.rs 9.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11
use borrow_check::nll::type_check;
N
Niko Matsakis 已提交
12 13
use build;
use rustc::hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
14
use rustc::mir::{Mir, Promoted};
15
use rustc::ty::TyCtxt;
16
use rustc::ty::query::Providers;
N
Niko Matsakis 已提交
17 18 19 20
use rustc::ty::steal::Steal;
use rustc::hir;
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
use rustc::util::nodemap::DefIdSet;
21
use rustc_data_structures::sync::Lrc;
22
use std::borrow::Cow;
N
Niko Matsakis 已提交
23
use syntax::ast;
24
use syntax_pos::Span;
N
Niko Matsakis 已提交
25

26
pub mod add_validation;
27
pub mod add_moves_for_packed_drops;
28
pub mod cleanup_post_borrowck;
A
Ariel Ben-Yehuda 已提交
29
pub mod check_unsafety;
30
pub mod simplify_branches;
31
pub mod simplify;
32
pub mod erase_regions;
33
pub mod no_landing_pads;
34 35
pub mod rustc_peek;
pub mod elaborate_drops;
36
pub mod add_call_guards;
37 38
pub mod promote_consts;
pub mod qualify_consts;
39
mod qualify_min_const_fn;
40
pub mod remove_noop_landing_pads;
41
pub mod dump_mir;
42
pub mod deaggregator;
43
pub mod instcombine;
44
pub mod copy_prop;
45
pub mod const_prop;
J
John Kåre Alsaker 已提交
46
pub mod generator;
47
pub mod inline;
48
pub mod lower_128bit;
49
pub mod uniform_array_move_out;
N
Niko Matsakis 已提交
50

51
pub(crate) fn provide(providers: &mut Providers) {
N
Niko Matsakis 已提交
52
    self::qualify_consts::provide(providers);
A
Ariel Ben-Yehuda 已提交
53
    self::check_unsafety::provide(providers);
N
Niko Matsakis 已提交
54
    *providers = Providers {
N
Niko Matsakis 已提交
55
        mir_keys,
56
        mir_built,
N
Niko Matsakis 已提交
57 58 59 60
        mir_const,
        mir_validated,
        optimized_mir,
        is_mir_available,
N
Niko Matsakis 已提交
61 62 63 64
        ..*providers
    };
}

N
Niko Matsakis 已提交
65 66 67 68 69 70 71
fn is_mir_available<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> bool {
    tcx.mir_keys(def_id.krate).contains(&def_id)
}

/// Finds the full set of def-ids within the current crate that have
/// MIR associated with them.
fn mir_keys<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, krate: CrateNum)
72
                      -> Lrc<DefIdSet> {
N
Niko Matsakis 已提交
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
    assert_eq!(krate, LOCAL_CRATE);

    let mut set = DefIdSet();

    // All body-owners have MIR associated with them.
    set.extend(tcx.body_owners());

    // Additionally, tuple struct/variant constructors have MIR, but
    // they don't have a BodyId, so we need to build them separately.
    struct GatherCtors<'a, 'tcx: 'a> {
        tcx: TyCtxt<'a, 'tcx, 'tcx>,
        set: &'a mut DefIdSet,
    }
    impl<'a, 'tcx> Visitor<'tcx> for GatherCtors<'a, 'tcx> {
        fn visit_variant_data(&mut self,
                              v: &'tcx hir::VariantData,
                              _: ast::Name,
                              _: &'tcx hir::Generics,
                              _: ast::NodeId,
                              _: Span) {
            if let hir::VariantData::Tuple(_, node_id) = *v {
                self.set.insert(self.tcx.hir.local_def_id(node_id));
            }
            intravisit::walk_struct_def(self, v)
        }
        fn nested_visit_map<'b>(&'b mut self) -> NestedVisitorMap<'b, 'tcx> {
            NestedVisitorMap::None
        }
    }
    tcx.hir.krate().visit_all_item_likes(&mut GatherCtors {
103
        tcx,
N
Niko Matsakis 已提交
104 105 106
        set: &mut set,
    }.as_deep_visitor());

107
    Lrc::new(set)
N
Niko Matsakis 已提交
108 109
}

110 111 112 113 114
fn mir_built<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    let mir = build::mir_build(tcx, def_id);
    tcx.alloc_steal_mir(mir)
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/// Where a specific Mir comes from.
#[derive(Debug, Copy, Clone)]
pub struct MirSource {
    pub def_id: DefId,

    /// If `Some`, this is a promoted rvalue within the parent function.
    pub promoted: Option<Promoted>,
}

impl MirSource {
    pub fn item(def_id: DefId) -> Self {
        MirSource {
            def_id,
            promoted: None
        }
    }
}

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
/// Generates a default name for the pass based on the name of the
/// type `T`.
pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
    let name = unsafe { ::std::intrinsics::type_name::<T>() };
    if let Some(tail) = name.rfind(":") {
        Cow::from(&name[tail+1..])
    } else {
        Cow::from(name)
    }
}

/// A streamlined trait that you can implement to create a pass; the
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
pub trait MirPass {
    fn name<'a>(&'a self) -> Cow<'a, str> {
        default_name::<Self>()
    }

    fn run_pass<'a, 'tcx>(&self,
                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          source: MirSource,
                          mir: &mut Mir<'tcx>);
}

158
pub macro run_passes($tcx:ident, $mir:ident, $def_id:ident, $suite_index:expr; $($pass:expr,)*) {{
159
    let suite_index: usize = $suite_index;
160 161 162 163 164
    let run_passes = |mir: &mut _, promoted| {
        let source = MirSource {
            def_id: $def_id,
            promoted
        };
165
        let mut index = 0;
M
Manish Goregaokar 已提交
166
        let mut run_pass = |pass: &dyn MirPass| {
167 168 169 170 171 172 173 174 175 176 177 178
            let run_hooks = |mir: &_, index, is_after| {
                dump_mir::on_mir_pass($tcx, &format_args!("{:03}-{:03}", suite_index, index),
                                      &pass.name(), source, mir, is_after);
            };
            run_hooks(mir, index, false);
            pass.run_pass($tcx, source, mir);
            run_hooks(mir, index, true);

            index += 1;
        };
        $(run_pass(&$pass);)*
    };
179 180

    run_passes(&mut $mir, None);
181

182
    for (index, promoted_mir) in $mir.promoted.iter_enumerated_mut() {
183
        run_passes(promoted_mir, Some(index));
184

185 186
        // Let's make sure we don't miss any nested instances
        assert!(promoted_mir.promoted.is_empty());
187
    }
188
}}
189

190 191 192
fn mir_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
    // Unsafety check uses the raw mir, so make sure it is run
    let _ = tcx.unsafety_check_result(def_id);
193

194
    let mut mir = tcx.mir_built(def_id).steal();
195
    run_passes![tcx, mir, def_id, 0;
196 197
        // Remove all `EndRegion` statements that are not involved in borrows.
        cleanup_post_borrowck::CleanEndRegions,
198 199 200 201 202

        // What we need to do constant evaluation.
        simplify::SimplifyCfg::new("initial"),
        type_check::TypeckMir,
        rustc_peek::SanityCheck,
203
        uniform_array_move_out::UniformArrayMoveOut,
204 205 206
    ];
    tcx.alloc_steal_mir(mir)
}
207

208
fn mir_validated<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Steal<Mir<'tcx>> {
209 210
    let node_id = tcx.hir.as_local_node_id(def_id).unwrap();
    if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(node_id) {
211 212 213
        // Ensure that we compute the `mir_const_qualif` for constants at
        // this point, before we steal the mir-const result.
        let _ = tcx.mir_const_qualif(def_id);
214 215
    }

216
    let mut mir = tcx.mir_const(def_id).steal();
217
    run_passes![tcx, mir, def_id, 1;
218 219 220 221 222
        // What we need to run borrowck etc.
        qualify_consts::QualifyAndPromoteConstants,
        simplify::SimplifyCfg::new("qualify-consts"),
    ];
    tcx.alloc_steal_mir(mir)
223 224
}

225 226 227 228
fn optimized_mir<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> &'tcx Mir<'tcx> {
    // (Mir-)Borrowck uses `mir_validated`, so we have to force it to
    // execute before we can steal.
    let _ = tcx.mir_borrowck(def_id);
229 230 231 232

    if tcx.use_ast_borrowck() {
        let _ = tcx.borrowck(def_id);
    }
233

234
    let mut mir = tcx.mir_validated(def_id).steal();
235
    run_passes![tcx, mir, def_id, 2;
236
        // Remove all things not needed by analysis
237 238
        no_landing_pads::NoLandingPads,
        simplify_branches::SimplifyBranches::new("initial"),
239 240
        remove_noop_landing_pads::RemoveNoopLandingPads,
        simplify::SimplifyCfg::new("early-opt"),
241 242
        // Remove all `AscribeUserType` statements.
        cleanup_post_borrowck::CleanAscribeUserType,
243 244 245 246 247 248 249 250 251

        // These next passes must be executed together
        add_call_guards::CriticalCallEdges,
        elaborate_drops::ElaborateDrops,
        no_landing_pads::NoLandingPads,
        // AddValidation needs to run after ElaborateDrops and before EraseRegions, and it needs
        // an AllCallEdges pass right before it.
        add_call_guards::AllCallEdges,
        add_validation::AddValidation,
252 253 254 255
        // AddMovesForPackedDrops needs to run after drop
        // elaboration.
        add_moves_for_packed_drops::AddMovesForPackedDrops,

256
        simplify::SimplifyCfg::new("elaborate-drops"),
257

258 259 260 261 262
        // No lifetime analysis based on borrowing can be done from here on out.

        // From here on out, regions are gone.
        erase_regions::EraseRegions,

263 264
        lower_128bit::Lower128Bit,

265

266
        // Optimizations begin.
267
        uniform_array_move_out::RestoreSubsliceArrayMoveOut,
268
        inline::Inline,
269 270 271 272 273

        // Lowering generator control-flow and variables
        // has to happen before we do anything else to them.
        generator::StateTransform,

274
        instcombine::InstCombine,
275
        const_prop::ConstProp,
276
        simplify_branches::SimplifyBranches::new("after-const-prop"),
277 278
        deaggregator::Deaggregator,
        copy_prop::CopyPropagation,
279
        remove_noop_landing_pads::RemoveNoopLandingPads,
280
        simplify::SimplifyCfg::new("final"),
281 282 283
        simplify::SimplifyLocals,

        add_call_guards::CriticalCallEdges,
I
Irina Popa 已提交
284
        dump_mir::Marker("PreCodegen"),
285 286
    ];
    tcx.alloc_mir(mir)
287
}