1 //! Performs various peephole optimizations.
3 use crate::transform
::{MirPass, MirSource}
;
4 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
5 use rustc_hir
::Mutability
;
6 use rustc_index
::vec
::Idx
;
7 use rustc_middle
::mir
::visit
::{MutVisitor, Visitor}
;
8 use rustc_middle
::mir
::{
9 Body
, Constant
, Local
, Location
, Operand
, Place
, PlaceRef
, ProjectionElem
, Rvalue
,
11 use rustc_middle
::ty
::{self, TyCtxt}
;
14 pub struct InstCombine
;
16 impl<'tcx
> MirPass
<'tcx
> for InstCombine
{
17 fn run_pass(&self, tcx
: TyCtxt
<'tcx
>, _
: MirSource
<'tcx
>, body
: &mut Body
<'tcx
>) {
18 // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
19 // read-only so that we can do global analyses on the MIR in the process (e.g.
22 let mut optimization_finder
= OptimizationFinder
::new(body
, tcx
);
23 optimization_finder
.visit_body(body
);
24 optimization_finder
.optimizations
27 // Then carry out those optimizations.
28 MutVisitor
::visit_body(&mut InstCombineVisitor { optimizations, tcx }
, body
);
32 pub struct InstCombineVisitor
<'tcx
> {
33 optimizations
: OptimizationList
<'tcx
>,
37 impl<'tcx
> MutVisitor
<'tcx
> for InstCombineVisitor
<'tcx
> {
38 fn tcx(&self) -> TyCtxt
<'tcx
> {
42 fn visit_rvalue(&mut self, rvalue
: &mut Rvalue
<'tcx
>, location
: Location
) {
43 if self.optimizations
.and_stars
.remove(&location
) {
44 debug
!("replacing `&*`: {:?}", rvalue
);
45 let new_place
= match rvalue
{
46 Rvalue
::Ref(_
, _
, place
) => {
47 if let &[ref proj_l @
.., proj_r
] = place
.projection
.as_ref() {
48 place
.projection
= self.tcx().intern_place_elems(&[proj_r
]);
52 local
: mem
::replace(&mut place
.local
, Local
::new(0)),
53 projection
: self.tcx().intern_place_elems(proj_l
),
59 _
=> bug
!("Detected `&*` but didn't find `&*`!"),
61 *rvalue
= Rvalue
::Use(Operand
::Copy(new_place
))
64 if let Some(constant
) = self.optimizations
.arrays_lengths
.remove(&location
) {
65 debug
!("replacing `Len([_; N])`: {:?}", rvalue
);
66 *rvalue
= Rvalue
::Use(Operand
::Constant(box constant
));
69 self.super_rvalue(rvalue
, location
)
73 /// Finds optimization opportunities on the MIR.
74 struct OptimizationFinder
<'b
, 'tcx
> {
77 optimizations
: OptimizationList
<'tcx
>,
80 impl OptimizationFinder
<'b
, 'tcx
> {
81 fn new(body
: &'b Body
<'tcx
>, tcx
: TyCtxt
<'tcx
>) -> OptimizationFinder
<'b
, 'tcx
> {
82 OptimizationFinder { body, tcx, optimizations: OptimizationList::default() }
86 impl Visitor
<'tcx
> for OptimizationFinder
<'b
, 'tcx
> {
87 fn visit_rvalue(&mut self, rvalue
: &Rvalue
<'tcx
>, location
: Location
) {
88 if let Rvalue
::Ref(_
, _
, place
) = rvalue
{
89 if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] }
=
92 // The dereferenced place must have type `&_`.
93 let ty
= Place
::ty_from(local
, proj_base
, self.body
, self.tcx
).ty
;
94 if let ty
::Ref(_
, _
, Mutability
::Not
) = ty
.kind
{
95 self.optimizations
.and_stars
.insert(location
);
100 if let Rvalue
::Len(ref place
) = *rvalue
{
101 let place_ty
= place
.ty(&self.body
.local_decls
, self.tcx
).ty
;
102 if let ty
::Array(_
, len
) = place_ty
.kind
{
103 let span
= self.body
.source_info(location
).span
;
104 let constant
= Constant { span, literal: len, user_ty: None }
;
105 self.optimizations
.arrays_lengths
.insert(location
, constant
);
109 self.super_rvalue(rvalue
, location
)
114 struct OptimizationList
<'tcx
> {
115 and_stars
: FxHashSet
<Location
>,
116 arrays_lengths
: FxHashMap
<Location
, Constant
<'tcx
>>,