Skip to content

Commit 64c086d

Browse files
committed
Auto merge of #68031 - Marwes:fold_list, r=<try>
perf: Avoid creating a SmallVec if nothing changes during a fold Not sure if this helps but in theory it should be less work than what the current micro optimization does for `ty::Predicate` lists. (It would explain the overhead I am seeing from `perf`.)
2 parents 4884061 + a1586f1 commit 64c086d

File tree

1 file changed

+35
-17
lines changed

1 file changed

+35
-17
lines changed

src/librustc/ty/structural_impls.rs

Lines changed: 35 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -797,8 +797,7 @@ impl<'tcx, T: TypeFoldable<'tcx>> TypeFoldable<'tcx> for ty::Binder<T> {
797797

798798
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>> {
799799
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
800-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
801-
folder.tcx().intern_existential_predicates(&v)
800+
fold_list(*self, folder, |tcx, v| tcx.intern_existential_predicates(v))
802801
}
803802

804803
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -808,8 +807,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::ExistentialPredicate<'tcx>>
808807

809808
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
810809
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
811-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
812-
folder.tcx().intern_type_list(&v)
810+
fold_list(*self, folder, |tcx, v| tcx.intern_type_list(v))
813811
}
814812

815813
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -819,8 +817,7 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<Ty<'tcx>> {
819817

820818
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ProjectionKind> {
821819
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
822-
let v = self.iter().map(|t| t.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
823-
folder.tcx().intern_projs(&v)
820+
fold_list(*self, folder, |tcx, v| tcx.intern_projs(v))
824821
}
825822

826823
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -984,17 +981,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Region<'tcx> {
984981

985982
impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<ty::Predicate<'tcx>> {
986983
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
987-
// This code is hot enough that it's worth specializing for a list of
988-
// length 0. (No other length is common enough to be worth singling
989-
// out).
990-
if self.len() == 0 {
991-
self
992-
} else {
993-
// Don't bother interning if nothing changed, which is the common
994-
// case.
995-
let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
996-
if v[..] == self[..] { self } else { folder.tcx().intern_predicates(&v) }
997-
}
984+
fold_list(*self, folder, |tcx, v| tcx.intern_predicates(v))
998985
}
999986

1000987
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
@@ -1067,3 +1054,34 @@ impl<'tcx> TypeFoldable<'tcx> for InferConst<'tcx> {
10671054
false
10681055
}
10691056
}
1057+
1058+
// Does the equivalent of
1059+
// ```
1060+
// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
1061+
// folder.tcx().intern_*(&v)
1062+
// ```
1063+
fn fold_list<'tcx, F, T>(
1064+
list: &'tcx ty::List<T>,
1065+
folder: &mut F,
1066+
intern: impl FnOnce(TyCtxt<'tcx>, &[T]) -> &'tcx ty::List<T>,
1067+
) -> &'tcx ty::List<T>
1068+
where
1069+
F: TypeFolder<'tcx>,
1070+
T: TypeFoldable<'tcx> + PartialEq + Copy,
1071+
{
1072+
let mut iter = list.iter();
1073+
// Look for the first element that changed
1074+
if let Some((i, new_t)) = iter.by_ref().enumerate().find_map(|(i, t)| {
1075+
let new_t = t.fold_with(folder);
1076+
if new_t == *t { None } else { Some((i, new_t)) }
1077+
}) {
1078+
// An element changed, prepare to intern the resulting list
1079+
let mut new_list = SmallVec::<[_; 8]>::with_capacity(list.len());
1080+
new_list.extend_from_slice(&list[..i]);
1081+
new_list.push(new_t);
1082+
new_list.extend(iter.map(|t| t.fold_with(folder)));
1083+
intern(folder.tcx(), &new_list)
1084+
} else {
1085+
list
1086+
}
1087+
}

0 commit comments

Comments
 (0)