Skip to content

Commit e8a44d2

Browse files
committed
librustc_mir: Remove &*x when x has a reference type.
This introduces a new `InstCombine` pass for us to place such peephole optimizations.
1 parent 8394685 commit e8a44d2

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

src/librustc_driver/driver.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1017,13 +1017,16 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
10171017
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
10181018
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads"));
10191019

1020+
// From here on out, regions are gone.
10201021
passes.push_pass(box mir::transform::erase_regions::EraseRegions);
10211022

10221023
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
10231024
passes.push_pass(box borrowck::ElaborateDrops);
10241025
passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
10251026
passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops"));
10261027

1028+
// No lifetime analysis based on borrowing can be done from here on out.
1029+
passes.push_pass(box mir::transform::instcombine::InstCombine::new());
10271030
passes.push_pass(box mir::transform::deaggregator::Deaggregator);
10281031

10291032
passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+

src/librustc_mir/transform/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ pub mod promote_consts;
1818
pub mod qualify_consts;
1919
pub mod dump_mir;
2020
pub mod deaggregator;
21+
pub mod instcombine;
22+

0 commit comments

Comments
 (0)