Avoid SmallVec::collect() in SubstsRef::super_fold_with().

This commit reduces instruction counts for several benchmarks by up to
5%.
This commit is contained in:
Nicholas Nethercote 2019-10-01 10:25:45 +10:00
parent 06c68947ad
commit 14192607d3

View File

@ -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)
}
}
}
}