1 //! Performs various peephole optimizations.
3 use rustc::mir::{Constant, Location, Place, PlaceBase, Body, Operand, ProjectionElem, Rvalue,
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;
10 use crate::transform::{MirPass, MirSource};
12 pub struct InstCombine;
14 impl MirPass for InstCombine {
15 fn run_pass<'a, 'tcx>(&self,
16 tcx: TyCtxt<'a, 'tcx, 'tcx>,
18 mir: &mut Body<'tcx>) {
19 // We only run when optimizing MIR (at any level).
20 if tcx.sess.opts.debugging_opts.mir_opt_level == 0 {
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.
28 let mut optimization_finder = OptimizationFinder::new(mir, tcx);
29 optimization_finder.visit_body(mir);
30 optimization_finder.optimizations
33 // Then carry out those optimizations.
34 MutVisitor::visit_body(&mut InstCombineVisitor { optimizations }, mir);
38 pub struct InstCombineVisitor<'tcx> {
39 optimizations: OptimizationList<'tcx>,
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)) => {
49 mem::replace(&mut projection.base, Place::Base(PlaceBase::Local(Local::new(0))))
51 _ => bug!("Detected `&*` but didn't find `&*`!"),
53 *rvalue = Rvalue::Use(Operand::Copy(new_place))
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));
61 self.super_rvalue(rvalue, location)
65 /// Finds optimization opportunities on the MIR.
66 struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> {
68 tcx: TyCtxt<'a, 'tcx, 'tcx>,
69 optimizations: OptimizationList<'tcx>,
72 impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
73 fn new(mir: &'b Body<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> {
77 optimizations: OptimizationList::default(),
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.mir, self.tcx).ty.is_region_ptr() {
87 self.optimizations.and_stars.insert(location);
92 if let Rvalue::Len(ref place) = *rvalue {
93 let place_ty = place.ty(&self.mir.local_decls, self.tcx).ty;
94 if let ty::Array(_, len) = place_ty.sty {
95 let span = self.mir.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);
102 self.super_rvalue(rvalue, location)
107 struct OptimizationList<'tcx> {
108 and_stars: FxHashSet<Location>,
109 arrays_lengths: FxHashMap<Location, Constant<'tcx>>,