about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2016-09-10 14:33:29 -0700
committerPatrick Walton <pcwalton@mimiga.net>2016-09-16 09:30:51 -0700
commite8a44d29b633412b4173be8f1bfb6dae7ac3c45e (patch)
tree984f019eca3225a1d3e8522098c37e45812039f5
parent8394685b8385156fc4bc31cfbc693867e276d9d7 (diff)
downloadrust-e8a44d29b633412b4173be8f1bfb6dae7ac3c45e.tar.gz
rust-e8a44d29b633412b4173be8f1bfb6dae7ac3c45e.zip
librustc_mir: Remove `&*x` when `x` has a reference type.
This introduces a new `InstCombine` pass for us to place such peephole
optimizations.
-rw-r--r--src/librustc_driver/driver.rs3
-rw-r--r--src/librustc_mir/transform/instcombine.rs110
-rw-r--r--src/librustc_mir/transform/mod.rs2
3 files changed, 115 insertions, 0 deletions
diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs
index 36e9fccdf5f..14cd05279b1 100644
--- a/src/librustc_driver/driver.rs
+++ b/src/librustc_driver/driver.rs
@@ -1017,6 +1017,7 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
         passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("no-landing-pads"));
 
+        // From here on out, regions are gone.
         passes.push_pass(box mir::transform::erase_regions::EraseRegions);
 
         passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
@@ -1024,6 +1025,8 @@ pub fn phase_4_translate_to_llvm<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         passes.push_pass(box mir::transform::no_landing_pads::NoLandingPads);
         passes.push_pass(box mir::transform::simplify_cfg::SimplifyCfg::new("elaborate-drops"));
 
+        // No lifetime analysis based on borrowing can be done from here on out.
+        passes.push_pass(box mir::transform::instcombine::InstCombine::new());
         passes.push_pass(box mir::transform::deaggregator::Deaggregator);
 
         passes.push_pass(box mir::transform::add_call_guards::AddCallGuards);
diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs
new file mode 100644
index 00000000000..a0331f03b01
--- /dev/null
+++ b/src/librustc_mir/transform/instcombine.rs
@@ -0,0 +1,110 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Performs various peephole optimizations.
+
+use rustc::mir::repr::{Location, Lvalue, Mir, Operand, ProjectionElem, Rvalue};
+use rustc::mir::transform::{MirPass, MirSource, Pass};
+use rustc::mir::visit::{MutVisitor, Visitor};
+use rustc::ty::TyCtxt;
+use rustc::util::nodemap::FnvHashSet;
+use std::mem;
+
+pub struct InstCombine {
+    optimizations: OptimizationList,
+}
+
+impl InstCombine {
+    pub fn new() -> InstCombine {
+        InstCombine {
+            optimizations: OptimizationList::default(),
+        }
+    }
+}
+
+impl Pass for InstCombine {}
+
+impl<'tcx> MirPass<'tcx> for InstCombine {
+    fn run_pass<'a>(&mut self,
+                    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                    _: MirSource,
+                    mir: &mut Mir<'tcx>) {
+        // We only run when optimizing MIR (at any level).
+        if tcx.sess.opts.debugging_opts.mir_opt_level == Some(0) {
+            return
+        }
+
+        // First, find optimization opportunities. This is done in a pre-pass to keep the MIR
+        // read-only so that we can do global analyses on the MIR in the process (e.g.
+        // `Lvalue::ty()`).
+        {
+            let mut optimization_finder = OptimizationFinder::new(mir, tcx);
+            optimization_finder.visit_mir(mir);
+            self.optimizations = optimization_finder.optimizations
+        }
+
+        // Then carry out those optimizations.
+        MutVisitor::visit_mir(&mut *self, mir);
+    }
+}
+
+impl<'tcx> MutVisitor<'tcx> for InstCombine {
+    fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) {
+        if self.optimizations.and_stars.remove(&location) {
+            debug!("Replacing `&*`: {:?}", rvalue);
+            let new_lvalue = match *rvalue {
+                Rvalue::Ref(_, _, Lvalue::Projection(ref mut projection)) => {
+                    mem::replace(&mut projection.base, Lvalue::ReturnPointer)
+                }
+                _ => bug!("Detected `&*` but didn't find `&*`!"),
+            };
+            *rvalue = Rvalue::Use(Operand::Consume(new_lvalue))
+        }
+
+        self.super_rvalue(rvalue, location)
+    }
+}
+
+/// Finds optimization opportunities on the MIR.
+struct OptimizationFinder<'b, 'a, 'tcx:'a+'b> {
+    mir: &'b Mir<'tcx>,
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    optimizations: OptimizationList,
+}
+
+impl<'b, 'a, 'tcx:'b> OptimizationFinder<'b, 'a, 'tcx> {
+    fn new(mir: &'b Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> OptimizationFinder<'b, 'a, 'tcx> {
+        OptimizationFinder {
+            mir: mir,
+            tcx: tcx,
+            optimizations: OptimizationList::default(),
+        }
+    }
+}
+
+impl<'b, 'a, 'tcx> Visitor<'tcx> for OptimizationFinder<'b, 'a, 'tcx> {
+    fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
+        if let Rvalue::Ref(_, _, Lvalue::Projection(ref projection)) = *rvalue {
+            if let ProjectionElem::Deref = projection.elem {
+                if projection.base.ty(self.mir, self.tcx).to_ty(self.tcx).is_region_ptr() {
+                    self.optimizations.and_stars.insert(location);
+                }
+            }
+        }
+
+        self.super_rvalue(rvalue, location)
+    }
+}
+
+#[derive(Default)]
+struct OptimizationList {
+    and_stars: FnvHashSet<Location>,
+}
+
diff --git a/src/librustc_mir/transform/mod.rs b/src/librustc_mir/transform/mod.rs
index c3485b8256d..e99b7a976e3 100644
--- a/src/librustc_mir/transform/mod.rs
+++ b/src/librustc_mir/transform/mod.rs
@@ -18,3 +18,5 @@ pub mod promote_consts;
 pub mod qualify_consts;
 pub mod dump_mir;
 pub mod deaggregator;
+pub mod instcombine;
+