|  | 
|  | 1 | +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT | 
|  | 2 | +// file at the top-level directory of this distribution and at | 
|  | 3 | +// http://rust-lang.org/COPYRIGHT. | 
|  | 4 | +// | 
|  | 5 | +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | 
|  | 6 | +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | 
|  | 7 | +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | 
|  | 8 | +// option. This file may not be copied, modified, or distributed | 
|  | 9 | +// except according to those terms. | 
|  | 10 | + | 
|  | 11 | +//! Performs various peephole optimizations. | 
|  | 12 | +
 | 
|  | 13 | +use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue}; | 
|  | 14 | +use rustc::mir::transform::{MirPass, MirSource, Pass}; | 
|  | 15 | +use rustc::mir::visit::{MutVisitor, Visitor}; | 
|  | 16 | +use rustc::ty::TyCtxt; | 
|  | 17 | +use rustc::util::nodemap::FnvHashSet; | 
|  | 18 | +use std::mem; | 
|  | 19 | + | 
|  | 20 | +pub struct InstCombine { | 
|  | 21 | +    optimizations: OptimizationList, | 
|  | 22 | +} | 
|  | 23 | + | 
|  | 24 | +impl InstCombine { | 
|  | 25 | +    pub fn new() -> InstCombine { | 
|  | 26 | +        InstCombine { | 
|  | 27 | +            optimizations: OptimizationList::default(), | 
|  | 28 | +        } | 
|  | 29 | +    } | 
|  | 30 | +} | 
|  | 31 | + | 
|  | 32 | +impl Pass for InstCombine {} | 
|  | 33 | + | 
|  | 34 | +impl<'tcx> MirPass<'tcx> for InstCombine { | 
|  | 35 | +    fn run_pass<'a>(&mut self, | 
|  | 36 | +                    tcx: TyCtxt<'a, 'tcx, 'tcx>, | 
|  | 37 | +                    _: MirSource, | 
|  | 38 | +                    mir: &mut Mir<'tcx>) { | 
|  | 39 | +        // We only run when optimizing MIR (at any level). | 
|  | 40 | +        if tcx.sess.opts.debugging_opts.mir_opt_level == Some(0) { | 
|  | 41 | +            return | 
|  | 42 | +        } | 
|  | 43 | + | 
|  | 44 | +        // First, find optimization opportunities. This is done in a pre-pass to keep the MIR | 
|  | 45 | +        // read-only so that we can do global analyses on the MIR in the process (e.g. | 
|  | 46 | +        // `Lvalue::ty()`). | 
|  | 47 | +        { | 
|  | 48 | +            let mut optimization_finder = OptimizationFinder::new(mir, tcx); | 
|  | 49 | +            optimization_finder.visit_mir(mir); | 
|  | 50 | +            self.optimizations = optimization_finder.optimizations | 
|  | 51 | +        } | 
|  | 52 | + | 
|  | 53 | +        // Then carry out those optimizations. | 
|  | 54 | +        MutVisitor::visit_mir(&mut *self, mir); | 
|  | 55 | +    } | 
|  | 56 | +} | 
|  | 57 | + | 
|  | 58 | +impl<'tcx> MutVisitor<'tcx> for InstCombine { | 
|  | 59 | +    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { | 
|  | 60 | +        if self.optimizations.and_stars.remove(&location) { | 
|  | 61 | +            debug!("Replacing `&*`: {:?}", rvalue); | 
|  | 62 | +            let new_lvalue = match *rvalue { | 
|  | 63 | +                Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => { | 
|  | 64 | +                    mem::replace(&mut projection.base, Lvalue::ReturnPointer) | 
|  | 65 | +                } | 
|  | 66 | +                _ => bug!("Detected `&*` but didn't find `&*`!"), | 
|  | 67 | +            }; | 
|  | 68 | +            *rvalue = Rvalue::Use(Operand::Consume(new_lvalue)) | 
|  | 69 | +        } | 
|  | 70 | + | 
|  | 71 | +        self.super_rvalue(rvalue, location) | 
|  | 72 | +    } | 
|  | 73 | +} | 
|  | 74 | + | 
|  | 75 | +/// Finds optimization opportunities on the MIR. | 
|  | 76 | +struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> { | 
|  | 77 | +    mir: &'b Mir<'tcx>, | 
|  | 78 | +    tcx: TyCtxt<'a, 'tcx, 'tcx>, | 
|  | 79 | +    optimizations: OptimizationList, | 
|  | 80 | +} | 
|  | 81 | + | 
|  | 82 | +impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> { | 
|  | 83 | +    fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> { | 
|  | 84 | +        OptimizationFinder { | 
|  | 85 | +            mir: mir, | 
|  | 86 | +            tcx: tcx, | 
|  | 87 | +            optimizations: OptimizationList::default(), | 
|  | 88 | +        } | 
|  | 89 | +    } | 
|  | 90 | +} | 
|  | 91 | + | 
|  | 92 | +impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> { | 
|  | 93 | +    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { | 
|  | 94 | +        if let Rvalue::Ref(_, _, Lvalue::Projection(ref projection)) = *rvalue { | 
|  | 95 | +            if let ProjectionElem::Deref = projection.elem { | 
|  | 96 | +                if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() { | 
|  | 97 | +                    self.optimizations.and_stars.insert(location); | 
|  | 98 | +                } | 
|  | 99 | +            } | 
|  | 100 | +        } | 
|  | 101 | + | 
|  | 102 | +        self.super_rvalue(rvalue, location) | 
|  | 103 | +    } | 
|  | 104 | +} | 
|  | 105 | + | 
|  | 106 | +#[derive(Default)] | 
|  | 107 | +struct OptimizationList { | 
|  | 108 | +    and_stars: FnvHashSet<Location>, | 
|  | 109 | +} | 
|  | 110 | + | 
0 commit comments