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.
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.
11 //! Performs various peephole optimizations.
13 use rustc
::mir
::{Constant, Location, Place, Mir, Operand, ProjectionElem, Rvalue, Local}
;
14 use rustc
::mir
::visit
::{MutVisitor, Visitor}
;
15 use rustc
::ty
::{TyCtxt, TypeVariants}
;
16 use rustc
::util
::nodemap
::{FxHashMap, FxHashSet}
;
17 use rustc_data_structures
::indexed_vec
::Idx
;
19 use transform
::{MirPass, MirSource}
;
21 pub struct InstCombine
;
23 impl MirPass
for InstCombine
{
24 fn run_pass
<'a
, 'tcx
>(&self,
25 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
27 mir
: &mut Mir
<'tcx
>) {
28 // We only run when optimizing MIR (at any level).
29 if tcx
.sess
.opts
.debugging_opts
.mir_opt_level
== 0 {
33 // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
34 // read-only so that we can do global analyses on the MIR in the process (e.g.
37 let mut optimization_finder
= OptimizationFinder
::new(mir
, tcx
);
38 optimization_finder
.visit_mir(mir
);
39 optimization_finder
.optimizations
42 // Then carry out those optimizations.
43 MutVisitor
::visit_mir(&mut InstCombineVisitor { optimizations }
, mir
);
47 pub struct InstCombineVisitor
<'tcx
> {
48 optimizations
: OptimizationList
<'tcx
>,
51 impl<'tcx
> MutVisitor
<'tcx
> for InstCombineVisitor
<'tcx
> {
52 fn visit_rvalue(&mut self, rvalue
: &mut Rvalue
<'tcx
>, location
: Location
) {
53 if self.optimizations
.and_stars
.remove(&location
) {
54 debug
!("Replacing `&*`: {:?}", rvalue
);
55 let new_place
= match *rvalue
{
56 Rvalue
::Ref(_
, _
, Place
::Projection(ref mut projection
)) => {
58 mem
::replace(&mut projection
.base
, Place
::Local(Local
::new(0)))
60 _
=> bug
!("Detected `&*` but didn't find `&*`!"),
62 *rvalue
= Rvalue
::Use(Operand
::Copy(new_place
))
65 if let Some(constant
) = self.optimizations
.arrays_lengths
.remove(&location
) {
66 debug
!("Replacing `Len([_; N])`: {:?}", rvalue
);
67 *rvalue
= Rvalue
::Use(Operand
::Constant(box constant
));
70 self.super_rvalue(rvalue
, location
)
74 /// Finds optimization opportunities on the MIR.
75 struct OptimizationFinder
<'b
, 'a
, 'tcx
:'a
+'b
> {
77 tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>,
78 optimizations
: OptimizationList
<'tcx
>,
81 impl<'b
, 'a
, 'tcx
:'b
> OptimizationFinder
<'b
, 'a
, 'tcx
> {
82 fn new(mir
: &'b Mir
<'tcx
>, tcx
: TyCtxt
<'a
, 'tcx
, 'tcx
>) -> OptimizationFinder
<'b
, 'a
, 'tcx
> {
86 optimizations
: OptimizationList
::default(),
91 impl<'b
, 'a
, 'tcx
> Visitor
<'tcx
> for OptimizationFinder
<'b
, 'a
, 'tcx
> {
92 fn visit_rvalue(&mut self, rvalue
: &Rvalue
<'tcx
>, location
: Location
) {
93 if let Rvalue
::Ref(_
, _
, Place
::Projection(ref projection
)) = *rvalue
{
94 if let ProjectionElem
::Deref
= projection
.elem
{
95 if projection
.base
.ty(self.mir
, self.tcx
).to_ty(self.tcx
).is_region_ptr() {
96 self.optimizations
.and_stars
.insert(location
);
101 if let Rvalue
::Len(ref place
) = *rvalue
{
102 let place_ty
= place
.ty(&self.mir
.local_decls
, self.tcx
).to_ty(self.tcx
);
103 if let TypeVariants
::TyArray(_
, len
) = place_ty
.sty
{
104 let span
= self.mir
.source_info(location
).span
;
105 let ty
= self.tcx
.types
.usize;
106 let constant
= Constant { span, ty, literal: len }
;
107 self.optimizations
.arrays_lengths
.insert(location
, constant
);
111 self.super_rvalue(rvalue
, location
)
116 struct OptimizationList
<'tcx
> {
117 and_stars
: FxHashSet
<Location
>,
118 arrays_lengths
: FxHashMap
<Location
, Constant
<'tcx
>>,