]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/transform/instcombine.rs
Changed usages of `mir` in librustc::mir and librustc_mir to `body`
[rust.git] / src / librustc_mir / transform / instcombine.rs
1 //! Performs various peephole optimizations.
2
3 use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue,
4     Local};
5 use rustc::mir::visit::{MutVisitor, Visitor};
6 use rustc::ty::{self, TyCtxt};
7 use rustc::util::nodemap::{FxHashMap, FxHashSet};
8 use rustc_data_structures::indexed_vec::Idx;
9 use std::mem;
10 use crate::transform::{MirPass, MirSource};
11
12 pub struct InstCombine;
13
14 impl MirPass for InstCombine {
15     fn run_pass<'a, 'tcx>(&self,
16                           tcx: TyCtxt<'a, 'tcx, 'tcx>,
17                           _: MirSource<'tcx>,
18                           body: &mut Body<'tcx>) {
19         // We only run when optimizing MIR (at any level).
20         if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
21             return
22         }
23
24         // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
25         // read-only so that we can do global analyses on the MIR in the process (e.g.
26         // `Place::ty()`).
27         let optimizations = {
28             let mut optimization_finder = OptimizationFinder::new(body, tcx);
29             optimization_finder.visit_body(body);
30             optimization_finder.optimizations
31         };
32
33         // Then carry out those optimizations.
34         MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, body);
35     }
36 }
37
38 pub struct InstCombineVisitor<'tcx> {
39     optimizations: OptimizationList<'tcx>,
40 }
41
42 impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> {
43     fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
44         if self.optimizations.and_stars.remove(&location) {
45             debug!("Replacing `&*`: {:?}", rvalue);
46             let new_place = match *rvalue {
47                 Rvalue::Ref(_, _, Place::Projection(ref mut projection)) => {
48                     // Replace with dummy
49                     mem::replace(&mut projection.base, Place::Base(PlaceBase::Local(Local::new(0))))
50                 }
51                 _ => bug!("Detected `&*` but didn't find `&*`!"),
52             };
53             *rvalue = Rvalue::Use(Operand::Copy(new_place))
54         }
55
56         if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) {
57             debug!("Replacing `Len([_; N])`: {:?}", rvalue);
58             *rvalue = Rvalue::Use(Operand::Constant(box constant));
59         }
60
61         self.super_rvalue(rvalue, location)
62     }
63 }
64
65 /// Finds optimization opportunities on the MIR.
66 struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> {
67     body: &'b Body<'tcx>,
68     tcx: TyCtxt<'a, 'tcx, 'tcx>,
69     optimizations: OptimizationList<'tcx>,
70 }
71
72 impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
73     fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> {
74         OptimizationFinder {
75             body,
76             tcx,
77             optimizations: OptimizationList::default(),
78         }
79     }
80 }
81
82 impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
83     fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
84         if let Rvalue::Ref(_, _, Place::Projection(ref projection)) = *rvalue {
85             if let ProjectionElem::Deref = projection.elem {
86                 if projection.base.ty(self.body, self.tcx).ty.is_region_ptr() {
87                     self.optimizations.and_stars.insert(location);
88                 }
89             }
90         }
91
92         if let Rvalue::Len(ref place) = *rvalue {
93             let place_ty = place.ty(&self.body.local_decls, self.tcx).ty;
94             if let ty::Array(_, len) = place_ty.sty {
95                 let span = self.body.source_info(location).span;
96                 let ty = self.tcx.types.usize;
97                 let constant = Constant { span, ty, literal: len, user_ty: None };
98                 self.optimizations.arrays_lengths.insert(location, constant);
99             }
100         }
101
102         self.super_rvalue(rvalue, location)
103     }
104 }
105
106 #[derive(Default)]
107 struct OptimizationList<'tcx> {
108     and_stars: FxHashSet<Location>,
109     arrays_lengths: FxHashMap<Location, Constant<'tcx>>,
110 }