Skip to content

Commit d9a7393

Browse files
committed
Auto merge of #141652 - compiler-errors:more-collect-and-apply, r=lqd
Rework `collect_and_apply` to not rely on size hint for optimization I saw that we have quite a few `collect_and_apply` calls for N=3-7 (N=7 corresponding to cumulative 99% of nalgebra's calls). Didn't perf locally, but also this is super low-pri, so let's see what rust-timer says.
2 parents 792fc2b + 0479e74 commit d9a7393

File tree

1 file changed

+90
-46
lines changed

1 file changed

+90
-46
lines changed

compiler/rustc_type_ir/src/interner.rs

Lines changed: 90 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ use std::ops::Deref;
44

55
use rustc_ast_ir::Movability;
66
use rustc_index::bit_set::DenseBitSet;
7-
use smallvec::SmallVec;
87

98
use crate::fold::TypeFoldable;
109
use crate::inherent::*;
@@ -382,28 +381,45 @@ impl<T, R> CollectAndApply<T, R> for T {
382381
F: FnOnce(&[T]) -> R,
383382
{
384383
// This code is hot enough that it's worth specializing for the most
385-
// common length lists, to avoid the overhead of `SmallVec` creation.
386-
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
387-
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
388-
// `assert`.
389-
match iter.size_hint() {
390-
(0, Some(0)) => {
391-
assert!(iter.next().is_none());
392-
f(&[])
393-
}
394-
(1, Some(1)) => {
395-
let t0 = iter.next().unwrap();
396-
assert!(iter.next().is_none());
397-
f(&[t0])
398-
}
399-
(2, Some(2)) => {
400-
let t0 = iter.next().unwrap();
401-
let t1 = iter.next().unwrap();
402-
assert!(iter.next().is_none());
403-
f(&[t0, t1])
404-
}
405-
_ => f(&iter.collect::<SmallVec<[_; 8]>>()),
406-
}
384+
// common length lists, to avoid the overhead of `Vec` creation.
385+
386+
let Some(t0) = iter.next() else {
387+
return f(&[]);
388+
};
389+
390+
let Some(t1) = iter.next() else {
391+
return f(&[t0]);
392+
};
393+
394+
let Some(t2) = iter.next() else {
395+
return f(&[t0, t1]);
396+
};
397+
398+
let Some(t3) = iter.next() else {
399+
return f(&[t0, t1, t2]);
400+
};
401+
402+
let Some(t4) = iter.next() else {
403+
return f(&[t0, t1, t2, t3]);
404+
};
405+
406+
let Some(t5) = iter.next() else {
407+
return f(&[t0, t1, t2, t3, t4]);
408+
};
409+
410+
let Some(t6) = iter.next() else {
411+
return f(&[t0, t1, t2, t3, t4, t5]);
412+
};
413+
414+
let Some(t7) = iter.next() else {
415+
return f(&[t0, t1, t2, t3, t4, t5, t6]);
416+
};
417+
418+
let Some(t8) = iter.next() else {
419+
return f(&[t0, t1, t2, t3, t4, t5, t6, t7]);
420+
};
421+
422+
f(&[t0, t1, t2, t3, t4, t5, t6, t7, t8].into_iter().chain(iter).collect::<Vec<_>>())
407423
}
408424
}
409425

@@ -419,29 +435,57 @@ impl<T, R, E> CollectAndApply<T, R> for Result<T, E> {
419435
F: FnOnce(&[T]) -> R,
420436
{
421437
// This code is hot enough that it's worth specializing for the most
422-
// common length lists, to avoid the overhead of `SmallVec` creation.
423-
// Lengths 0, 1, and 2 typically account for ~95% of cases. If
424-
// `size_hint` is incorrect a panic will occur via an `unwrap` or an
425-
// `assert`, unless a failure happens first, in which case the result
426-
// will be an error anyway.
427-
Ok(match iter.size_hint() {
428-
(0, Some(0)) => {
429-
assert!(iter.next().is_none());
430-
f(&[])
431-
}
432-
(1, Some(1)) => {
433-
let t0 = iter.next().unwrap()?;
434-
assert!(iter.next().is_none());
435-
f(&[t0])
436-
}
437-
(2, Some(2)) => {
438-
let t0 = iter.next().unwrap()?;
439-
let t1 = iter.next().unwrap()?;
440-
assert!(iter.next().is_none());
441-
f(&[t0, t1])
442-
}
443-
_ => f(&iter.collect::<Result<SmallVec<[_; 8]>, _>>()?),
444-
})
438+
// common length lists, to avoid the overhead of `Vec` creation.
439+
440+
let Some(t0) = iter.next() else {
441+
return Ok(f(&[]));
442+
};
443+
let t0 = t0?;
444+
445+
let Some(t1) = iter.next() else {
446+
return Ok(f(&[t0]));
447+
};
448+
let t1 = t1?;
449+
450+
let Some(t2) = iter.next() else {
451+
return Ok(f(&[t0, t1]));
452+
};
453+
let t2 = t2?;
454+
455+
let Some(t3) = iter.next() else {
456+
return Ok(f(&[t0, t1, t2]));
457+
};
458+
let t3 = t3?;
459+
460+
let Some(t4) = iter.next() else {
461+
return Ok(f(&[t0, t1, t2, t3]));
462+
};
463+
let t4 = t4?;
464+
465+
let Some(t5) = iter.next() else {
466+
return Ok(f(&[t0, t1, t2, t3, t4]));
467+
};
468+
let t5 = t5?;
469+
470+
let Some(t6) = iter.next() else {
471+
return Ok(f(&[t0, t1, t2, t3, t4, t5]));
472+
};
473+
let t6 = t6?;
474+
475+
let Some(t7) = iter.next() else {
476+
return Ok(f(&[t0, t1, t2, t3, t4, t5, t6]));
477+
};
478+
let t7 = t7?;
479+
480+
let Some(t8) = iter.next() else {
481+
return Ok(f(&[t0, t1, t2, t3, t4, t5, t6, t7]));
482+
};
483+
let t8 = t8?;
484+
485+
Ok(f(&[Ok(t0), Ok(t1), Ok(t2), Ok(t3), Ok(t4), Ok(t5), Ok(t6), Ok(t7), Ok(t8)]
486+
.into_iter()
487+
.chain(iter)
488+
.collect::<Result<Vec<_>, _>>()?))
445489
}
446490
}
447491

0 commit comments

Comments
 (0)