about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorNicholas Nethercote <nnethercote@mozilla.com>2019-10-01 10:25:45 +1000
committerNicholas Nethercote <nnethercote@mozilla.com>2019-10-01 10:25:45 +1000
commit14192607d38f5501c75abea7a4a0e46349df5b5f (patch)
tree63c645c9d8017758b21a49e8d18afc7e63ad4c15 /src
parent06c68947ad88f22a8342fe6b54dc0fe54de6e011 (diff)
Avoid `SmallVec::collect()` in `SubstsRef::super_fold_with()`.
This commit reduces instruction counts for several benchmarks by up to
5%.
Diffstat (limited to 'src')
-rw-r--r--src/librustc/ty/subst.rs43
1 files changed, 35 insertions, 8 deletions
diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs
index e5bee3cfbd0..7d03881fff2 100644
--- a/src/librustc/ty/subst.rs
+++ b/src/librustc/ty/subst.rs
@@ -383,14 +383,41 @@ impl<'a, 'tcx> InternalSubsts<'tcx> {
 
 impl<'tcx> TypeFoldable<'tcx> for SubstsRef<'tcx> {
     fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
-        let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
-
-        // If folding doesn't change the substs, it's faster to avoid
-        // calling `mk_substs` and instead reuse the existing substs.
-        if params[..] == self[..] {
-            self
-        } else {
-            folder.tcx().intern_substs(&params)
+        // This code is hot enough that it's worth specializing for the most
+        // common length lists, to avoid the overhead of `SmallVec` creation.
+        // The match arms are in order of frequency. The 1, 2, and 0 cases are
+        // typically hit in 90--99.99% of cases. When folding doesn't change
+        // the substs, it's faster to reuse the existing substs rather than
+        // calling `intern_substs`.
+        match self.len() {
+            1 => {
+                let param0 = self[0].fold_with(folder);
+                if param0 == self[0] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&[param0])
+                }
+            }
+            2 => {
+                let param0 = self[0].fold_with(folder);
+                let param1 = self[1].fold_with(folder);
+                if param0 == self[0] && param1 == self[1] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&[param0, param1])
+                }
+            }
+            0 => {
+                self
+            }
+            _ => {
+                let params: SmallVec<[_; 8]> = self.iter().map(|k| k.fold_with(folder)).collect();
+                if params[..] == self[..] {
+                    self
+                } else {
+                    folder.tcx().intern_substs(&params)
+                }
+            }
         }
     }