From 14192607d38f5501c75abea7a4a0e46349df5b5f Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 1 Oct 2019 10:25:45 +1000 Subject: [PATCH] Avoid `SmallVec::collect()` in `SubstsRef::super_fold_with()`. This commit reduces instruction counts for several benchmarks by up to 5%. --- src/librustc/ty/subst.rs | 43 ++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/src/librustc/ty/subst.rs b/src/librustc/ty/subst.rs index e5bee3cfbd06..7d03881fff2c 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>(&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(¶ms) + // 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(¶ms) + } + } } }