Diff
Not logged in

Differences From Artifact [9339be6648]:

To Artifact [7cc651e42d]:


     4      4   //
     5      5   // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
     6      6   // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
     7      7   // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
     8      8   // option. This file may not be copied, modified, or distributed
     9      9   // except according to those terms.
    10     10   
    11         -use dep_graph::DepNode;
           11  +//! See [the README](README.md) for details on writing your own pass.
           12  +
    12     13   use hir;
           14  +use hir::def_id::DefId;
    13     15   use hir::map::DefPathData;
    14     16   use mir::{Mir, Promoted};
    15     17   use ty::TyCtxt;
           18  +use std::rc::Rc;
    16     19   use syntax::ast::NodeId;
    17         -use util::common::time;
    18     20   
    19     21   use std::borrow::Cow;
    20         -use std::fmt;
    21     22   
    22     23   /// Where a specific Mir comes from.
    23     24   #[derive(Debug, Copy, Clone)]
    24     25   pub enum MirSource {
    25     26       /// Functions and methods.
    26     27       Fn(NodeId),
    27     28   
................................................................................
    32     33       Static(NodeId, hir::Mutability),
    33     34   
    34     35       /// Promoted rvalues within a function.
    35     36       Promoted(NodeId, Promoted)
    36     37   }
    37     38   
    38     39   impl<'a, 'tcx> MirSource {
           40  +    pub fn from_local_def_id(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId) -> MirSource {
           41  +        let id = tcx.hir.as_local_node_id(def_id).expect("mir source requires local def-id");
           42  +        Self::from_node(tcx, id)
           43  +    }
           44  +
    39     45       pub fn from_node(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId) -> MirSource {
    40     46           use hir::*;
    41     47   
    42     48           // Handle constants in enum discriminants, types, and repeat expressions.
    43     49           let def_id = tcx.hir.local_def_id(id);
    44     50           let def_key = tcx.def_key(def_id);
    45     51           if def_key.disambiguated_data.data == DefPathData::Initializer {
................................................................................
    66     72               MirSource::Const(id) |
    67     73               MirSource::Static(id, _) |
    68     74               MirSource::Promoted(id, _) => id
    69     75           }
    70     76       }
    71     77   }
    72     78   
    73         -/// Various information about pass.
    74         -pub trait Pass {
    75         -    // fn should_run(Session) to check if pass should run?
    76         -    fn name<'a>(&self) -> Cow<'static, str> {
    77         -        let name = unsafe { ::std::intrinsics::type_name::<Self>() };
    78         -        if let Some(tail) = name.rfind(":") {
    79         -            Cow::from(&name[tail+1..])
    80         -        } else {
    81         -            Cow::from(name)
    82         -        }
           79  +/// Generates a default name for the pass based on the name of the
           80  +/// type `T`.
           81  +pub fn default_name<T: ?Sized>() -> Cow<'static, str> {
           82  +    let name = unsafe { ::std::intrinsics::type_name::<T>() };
           83  +    if let Some(tail) = name.rfind(":") {
           84  +        Cow::from(&name[tail+1..])
           85  +    } else {
           86  +        Cow::from(name)
    83     87       }
    84         -    fn disambiguator<'a>(&'a self) -> Option<Box<fmt::Display+'a>> { None }
    85     88   }
    86     89   
    87         -/// A pass which inspects the whole Mir map.
    88         -pub trait MirMapPass<'tcx>: Pass {
    89         -    fn run_pass<'a>(
    90         -        &mut self,
    91         -        tcx: TyCtxt<'a, 'tcx, 'tcx>,
    92         -        hooks: &mut [Box<for<'s> MirPassHook<'s>>]);
    93         -}
    94         -
    95         -pub trait MirPassHook<'tcx>: Pass {
    96         -    fn on_mir_pass<'a>(
    97         -        &mut self,
    98         -        tcx: TyCtxt<'a, 'tcx, 'tcx>,
    99         -        src: MirSource,
   100         -        mir: &Mir<'tcx>,
   101         -        pass: &Pass,
   102         -        is_after: bool
   103         -    );
   104         -}
   105         -
   106         -/// A pass which inspects Mir of functions in isolation.
   107         -pub trait MirPass<'tcx>: Pass {
   108         -    fn run_pass<'a>(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
   109         -                    src: MirSource, mir: &mut Mir<'tcx>);
           90  +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
           91  +pub struct MirSuite(pub usize);
           92  +
           93  +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
           94  +pub struct MirPassIndex(pub usize);
           95  +
           96  +/// A pass hook is invoked both before and after each pass executes.
           97  +/// This is primarily used to dump MIR for debugging.
           98  +///
           99  +/// You can tell whether this is before or after by inspecting the
          100  +/// `mir` parameter -- before the pass executes, it will be `None` (in
          101  +/// which case you can inspect the MIR from previous pass by executing
          102  +/// `mir_cx.read_previous_mir()`); after the pass executes, it will be
          103  +/// `Some()` with the result of the pass (in which case the output
          104  +/// from the previous pass is most likely stolen, so you would not
          105  +/// want to try and access it). If the pass is interprocedural, then
          106  +/// the hook will be invoked once per output.
          107  +pub trait PassHook {
          108  +    fn on_mir_pass<'a, 'tcx: 'a>(&self,
          109  +                                 tcx: TyCtxt<'a, 'tcx, 'tcx>,
          110  +                                 suite: MirSuite,
          111  +                                 pass_num: MirPassIndex,
          112  +                                 pass_name: &str,
          113  +                                 source: MirSource,
          114  +                                 mir: &Mir<'tcx>,
          115  +                                 is_after: bool);
   110    116   }
   111    117   
   112         -impl<'tcx, T: MirPass<'tcx>> MirMapPass<'tcx> for T {
   113         -    fn run_pass<'a>(&mut self,
   114         -                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
   115         -                    hooks: &mut [Box<for<'s> MirPassHook<'s>>])
   116         -    {
   117         -        let def_ids = tcx.maps.mir.borrow().keys();
   118         -        for def_id in def_ids {
   119         -            if !def_id.is_local() {
   120         -                continue;
   121         -            }
          118  +/// The full suite of types that identifies a particular
          119  +/// application of a pass to a def-id.
          120  +pub type PassId = (MirSuite, MirPassIndex, DefId);
   122    121   
   123         -            let _task = tcx.dep_graph.in_task(DepNode::Mir(def_id));
   124         -            let mir = &mut tcx.maps.mir.borrow()[&def_id].borrow_mut();
   125         -            tcx.dep_graph.write(DepNode::Mir(def_id));
          122  +/// A streamlined trait that you can implement to create a pass; the
          123  +/// pass will be named after the type, and it will consist of a main
          124  +/// loop that goes over each available MIR and applies `run_pass`.
          125  +pub trait MirPass {
          126  +    fn name<'a>(&'a self) -> Cow<'a, str> {
          127  +        default_name::<Self>()
          128  +    }
   126    129   
   127         -            let id = tcx.hir.as_local_node_id(def_id).unwrap();
   128         -            let src = MirSource::from_node(tcx, id);
   129         -
   130         -            for hook in &mut *hooks {
   131         -                hook.on_mir_pass(tcx, src, mir, self, false);
   132         -            }
   133         -            MirPass::run_pass(self, tcx, src, mir);
   134         -            for hook in &mut *hooks {
   135         -                hook.on_mir_pass(tcx, src, mir, self, true);
   136         -            }
   137         -
   138         -            for (i, mir) in mir.promoted.iter_enumerated_mut() {
   139         -                let src = MirSource::Promoted(id, i);
   140         -                for hook in &mut *hooks {
   141         -                    hook.on_mir_pass(tcx, src, mir, self, false);
   142         -                }
   143         -                MirPass::run_pass(self, tcx, src, mir);
   144         -                for hook in &mut *hooks {
   145         -                    hook.on_mir_pass(tcx, src, mir, self, true);
   146         -                }
   147         -            }
   148         -        }
   149         -    }
          130  +    fn run_pass<'a, 'tcx>(&self,
          131  +                          tcx: TyCtxt<'a, 'tcx, 'tcx>,
          132  +                          source: MirSource,
          133  +                          mir: &mut Mir<'tcx>);
   150    134   }
   151    135   
   152    136   /// A manager for MIR passes.
          137  +///
          138  +/// FIXME(#41712) -- it is unclear whether we should have this struct.
          139  +#[derive(Clone)]
   153    140   pub struct Passes {
   154         -    passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>,
   155         -    pass_hooks: Vec<Box<for<'tcx> MirPassHook<'tcx>>>,
   156         -    plugin_passes: Vec<Box<for<'tcx> MirMapPass<'tcx>>>
          141  +    pass_hooks: Vec<Rc<PassHook>>,
          142  +    suites: Vec<Vec<Rc<MirPass>>>,
   157    143   }
   158    144   
          145  +/// The number of "pass suites" that we have:
          146  +///
          147  +/// - ready for constant evaluation
          148  +/// - unopt
          149  +/// - optimized
          150  +pub const MIR_SUITES: usize = 3;
          151  +
          152  +/// Run the passes we need to do constant qualification and evaluation.
          153  +pub const MIR_CONST: MirSuite = MirSuite(0);
          154  +
          155  +/// Run the passes we need to consider the MIR validated and ready for borrowck etc.
          156  +pub const MIR_VALIDATED: MirSuite = MirSuite(1);
          157  +
          158  +/// Run the passes we need to consider the MIR *optimized*.
          159  +pub const MIR_OPTIMIZED: MirSuite = MirSuite(2);
          160  +
   159    161   impl<'a, 'tcx> Passes {
   160    162       pub fn new() -> Passes {
   161         -        let passes = Passes {
   162         -            passes: Vec::new(),
          163  +        Passes {
   163    164               pass_hooks: Vec::new(),
   164         -            plugin_passes: Vec::new()
   165         -        };
   166         -        passes
   167         -    }
   168         -
   169         -    pub fn run_passes(&mut self, tcx: TyCtxt<'a, 'tcx, 'tcx>) {
   170         -        let Passes { ref mut passes, ref mut plugin_passes, ref mut pass_hooks } = *self;
   171         -        for pass in plugin_passes.iter_mut().chain(passes.iter_mut()) {
   172         -            time(tcx.sess.time_passes(), &*pass.name(),
   173         -                 || pass.run_pass(tcx, pass_hooks));
          165  +            suites: (0..MIR_SUITES).map(|_| Vec::new()).collect(),
   174    166           }
   175    167       }
   176    168   
   177    169       /// Pushes a built-in pass.
   178         -    pub fn push_pass(&mut self, pass: Box<for<'b> MirMapPass<'b>>) {
   179         -        self.passes.push(pass);
          170  +    pub fn push_pass<T: MirPass + 'static>(&mut self, suite: MirSuite, pass: T) {
          171  +        self.suites[suite.0].push(Rc::new(pass));
   180    172       }
   181    173   
   182    174       /// Pushes a pass hook.
   183         -    pub fn push_hook(&mut self, hook: Box<for<'b> MirPassHook<'b>>) {
   184         -        self.pass_hooks.push(hook);
          175  +    pub fn push_hook<T: PassHook + 'static>(&mut self, hook: T) {
          176  +        self.pass_hooks.push(Rc::new(hook));
   185    177       }
   186         -}
          178  +
          179  +    pub fn passes(&self, suite: MirSuite) -> &[Rc<MirPass>] {
          180  +        &self.suites[suite.0]
          181  +    }
   187    182   
   188         -/// Copies the plugin passes.
   189         -impl ::std::iter::Extend<Box<for<'a> MirMapPass<'a>>> for Passes {
   190         -    fn extend<I: IntoIterator<Item=Box<for <'a> MirMapPass<'a>>>>(&mut self, it: I) {
   191         -        self.plugin_passes.extend(it);
          183  +    pub fn hooks(&self) -> &[Rc<PassHook>] {
          184  +        &self.pass_hooks
   192    185       }
   193    186   }