1 //! Performs various peephole optimizations.
3 use crate::transform
::{MirPass, MirSource}
;
4 use rustc_data_structures
::fx
::{FxHashMap, FxHashSet}
;
5 use rustc_index
::vec
::Idx
;
6 use rustc_middle
::mir
::visit
::{MutVisitor, Visitor}
;
7 use rustc_middle
::mir
::{
8 read_only
, Body
, BodyAndCache
, Constant
, Local
, Location
, Operand
, Place
, PlaceRef
,
9 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 BodyAndCache
<'tcx
>) {
18 // We only run when optimizing MIR (at any level).
19 if tcx
.sess
.opts
.debugging_opts
.mir_opt_level
== 0 {
23 // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
24 // read-only so that we can do global analyses on the MIR in the process (e.g.
27 let read_only_cache
= read_only
!(body
);
28 let mut optimization_finder
= OptimizationFinder
::new(body
, tcx
);
29 optimization_finder
.visit_body(&read_only_cache
);
30 optimization_finder
.optimizations
33 // Then carry out those optimizations.
34 MutVisitor
::visit_body(&mut InstCombineVisitor { optimizations, tcx }
, body
);
38 pub struct InstCombineVisitor
<'tcx
> {
39 optimizations
: OptimizationList
<'tcx
>,
43 impl<'tcx
> MutVisitor
<'tcx
> for InstCombineVisitor
<'tcx
> {
44 fn tcx(&self) -> TyCtxt
<'tcx
> {
48 fn visit_rvalue(&mut self, rvalue
: &mut Rvalue
<'tcx
>, location
: Location
) {
49 if self.optimizations
.and_stars
.remove(&location
) {
50 debug
!("replacing `&*`: {:?}", rvalue
);
51 let new_place
= match rvalue
{
52 Rvalue
::Ref(_
, _
, place
) => {
53 if let &[ref proj_l @
.., proj_r
] = place
.projection
.as_ref() {
54 place
.projection
= self.tcx().intern_place_elems(&[proj_r
]);
58 local
: mem
::replace(&mut place
.local
, Local
::new(0)),
59 projection
: self.tcx().intern_place_elems(proj_l
),
65 _
=> bug
!("Detected `&*` but didn't find `&*`!"),
67 *rvalue
= Rvalue
::Use(Operand
::Copy(new_place
))
70 if let Some(constant
) = self.optimizations
.arrays_lengths
.remove(&location
) {
71 debug
!("replacing `Len([_; N])`: {:?}", rvalue
);
72 *rvalue
= Rvalue
::Use(Operand
::Constant(box constant
));
75 self.super_rvalue(rvalue
, location
)
79 /// Finds optimization opportunities on the MIR.
80 struct OptimizationFinder
<'b
, 'tcx
> {
83 optimizations
: OptimizationList
<'tcx
>,
86 impl OptimizationFinder
<'b
, 'tcx
> {
87 fn new(body
: &'b Body
<'tcx
>, tcx
: TyCtxt
<'tcx
>) -> OptimizationFinder
<'b
, 'tcx
> {
88 OptimizationFinder { body, tcx, optimizations: OptimizationList::default() }
92 impl Visitor
<'tcx
> for OptimizationFinder
<'b
, 'tcx
> {
93 fn visit_rvalue(&mut self, rvalue
: &Rvalue
<'tcx
>, location
: Location
) {
94 if let Rvalue
::Ref(_
, _
, place
) = rvalue
{
95 if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] }
=
98 if Place
::ty_from(local
, proj_base
, self.body
, self.tcx
).ty
.is_region_ptr() {
99 self.optimizations
.and_stars
.insert(location
);
104 if let Rvalue
::Len(ref place
) = *rvalue
{
105 let place_ty
= place
.ty(&self.body
.local_decls
, self.tcx
).ty
;
106 if let ty
::Array(_
, len
) = place_ty
.kind
{
107 let span
= self.body
.source_info(location
).span
;
108 let constant
= Constant { span, literal: len, user_ty: None }
;
109 self.optimizations
.arrays_lengths
.insert(location
, constant
);
113 self.super_rvalue(rvalue
, location
)
118 struct OptimizationList
<'tcx
> {
119 and_stars
: FxHashSet
<Location
>,
120 arrays_lengths
: FxHashMap
<Location
, Constant
<'tcx
>>,