about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-06-20 01:39:43 +0000
committerbors <bors@rust-lang.org>2018-06-20 01:39:43 +0000
commit93a161170f6dd7b9f6605a23e332a07ab73fc804 (patch)
treecbe210ff67a7a45e2849a6e381ec73d688b178c6
parentac8d1f7623f55746ff8f59d6b26f03c39cee5844 (diff)
parentba0bb02f6ff241297281784d2aed7dd8c2c78c4d (diff)
downloadrust-93a161170f6dd7b9f6605a23e332a07ab73fc804.tar.gz
rust-93a161170f6dd7b9f6605a23e332a07ab73fc804.zip
Auto merge of #51617 - nnethercote:nll-allocs, r=pnkfelix
Reduce number of allocations done by NLL

A couple of easy wins. Here are the NLL speedups that exceed 1%:
```
sentry-cli-check
        avg: -3.5%      min: -3.5%      max: -3.5%
inflate-check
        avg: -1.9%      min: -1.9%      max: -1.9%
inflate
        avg: -1.7%      min: -1.7%      max: -1.7%
clap-rs-check
        avg: -1.6%      min: -1.6%      max: -1.6%
cargo-check
        avg: -1.6%      min: -1.6%      max: -1.6%
ripgrep-check
        avg: -1.4%      min: -1.4%      max: -1.4%
serde-check
        avg: -1.2%      min: -1.2%      max: -1.2%
regex-check
        avg: -1.0%      min: -1.0%      max: -1.0%
sentry-cli
        avg: -1.0%      min: -1.0%      max: -1.0%
```
r? @nikomatsakis
-rw-r--r--src/librustc_mir/borrow_check/path_utils.rs5
-rw-r--r--src/librustc_mir/dataflow/at_location.rs29
2 files changed, 21 insertions, 13 deletions
diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/src/librustc_mir/borrow_check/path_utils.rs
index 4871d427d07..b692ffbb250 100644
--- a/src/librustc_mir/borrow_check/path_utils.rs
+++ b/src/librustc_mir/borrow_check/path_utils.rs
@@ -21,6 +21,7 @@ use rustc::mir::{BasicBlock, Location, Mir, Place};
 use rustc::mir::{Projection, ProjectionElem, BorrowKind};
 use rustc::ty::{self, TyCtxt};
 use rustc_data_structures::control_flow_graph::dominators::Dominators;
+use rustc_data_structures::small_vec::SmallVec;
 use std::iter;
 
 pub(super) fn allow_two_phase_borrow<'a, 'tcx, 'gcx: 'tcx>(
@@ -259,8 +260,8 @@ pub(super) fn places_conflict<'a, 'gcx: 'tcx, 'tcx>(
 
 /// Return all the prefixes of `place` in reverse order, including
 /// downcasts.
-fn place_elements<'a, 'tcx>(place: &'a Place<'tcx>) -> Vec<&'a Place<'tcx>> {
-    let mut result = vec![];
+fn place_elements<'a, 'tcx>(place: &'a Place<'tcx>) -> SmallVec<[&'a Place<'tcx>; 8]> {
+    let mut result = SmallVec::new();
     let mut place = place;
     loop {
         result.push(place);
diff --git a/src/librustc_mir/dataflow/at_location.rs b/src/librustc_mir/dataflow/at_location.rs
index 0fbb54e8e0a..a89d1afae86 100644
--- a/src/librustc_mir/dataflow/at_location.rs
+++ b/src/librustc_mir/dataflow/at_location.rs
@@ -204,10 +204,22 @@ where
     T: HasMoveData<'tcx> + BitDenotation<Idx = MovePathIndex>,
 {
     pub fn has_any_child_of(&self, mpi: T::Idx) -> Option<T::Idx> {
+        // We process `mpi` before the loop below, for two reasons:
+        // - it's a little different from the loop case (we don't traverse its
+        //   siblings);
+        // - ~99% of the time the loop isn't reached, and this code is hot, so
+        //   we don't want to allocate `todo` unnecessarily.
+        if self.contains(&mpi) {
+            return Some(mpi);
+        }
         let move_data = self.operator().move_data();
+        let move_path = &move_data.move_paths[mpi];
+        let mut todo = if let Some(child) = move_path.first_child {
+            vec![child]
+        } else {
+            return None;
+        };
 
-        let mut todo = vec![mpi];
-        let mut push_siblings = false; // don't look at siblings of original `mpi`.
         while let Some(mpi) = todo.pop() {
             if self.contains(&mpi) {
                 return Some(mpi);
@@ -216,15 +228,10 @@ where
             if let Some(child) = move_path.first_child {
                 todo.push(child);
             }
-            if push_siblings {
-                if let Some(sibling) = move_path.next_sibling {
-                    todo.push(sibling);
-                }
-            } else {
-                // after we've processed the original `mpi`, we should
-                // always traverse the siblings of any of its
-                // children.
-                push_siblings = true;
+            // After we've processed the original `mpi`, we should always
+            // traverse the siblings of any of its children.
+            if let Some(sibling) = move_path.next_sibling {
+                todo.push(sibling);
             }
         }
         return None;