Skip to content

Commit acf7d4d

Browse files
committed
Specialize the stalled_on handling in process_obligation().
Optimizing for the common numbers of entries in `stalled_on` wins about 4% on `keccak` and `inflate`.
1 parent aaff05b commit acf7d4d

File tree

2 files changed

+38
-21
lines changed

2 files changed

+38
-21
lines changed

src/librustc/infer/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1600,8 +1600,8 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
16001600

16011601
// `resolver.shallow_resolve_changed(ty)` is equivalent to
16021602
// `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always
1603-
// inlined, despite being large, because it has a single call site that is
1604-
// extremely hot.
1603+
// inlined, despite being large, because it has only two call sites that
1604+
// are extremely hot.
16051605
#[inline(always)]
16061606
pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
16071607
match typ.sty {

src/librustc/traits/fulfill.rs

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -256,29 +256,46 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
256256
&mut self,
257257
pending_obligation: &mut Self::Obligation,
258258
) -> ProcessResult<Self::Obligation, Self::Error> {
259-
// If we were stalled on some unresolved variables, first check
260-
// whether any of them have been resolved; if not, don't bother
261-
// doing more work yet
262-
if !pending_obligation.stalled_on.is_empty() {
263-
let mut changed = false;
264-
// This `for` loop was once a call to `all()`, but this lower-level
265-
// form was a perf win. See #64545 for details.
266-
for &ty in &pending_obligation.stalled_on {
267-
if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
268-
changed = true;
269-
break;
270-
}
259+
// If we were stalled on some unresolved variables, first check whether
260+
// any of them have been resolved; if not, don't bother doing more work
261+
// yet.
262+
let change = match pending_obligation.stalled_on.len() {
263+
// Match arms are in order of frequency, which matters because this
264+
// code is so hot. 1 and 0 dominate; 2+ is fairly rare.
265+
1 => {
266+
let ty = pending_obligation.stalled_on[0];
267+
ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty)
268+
}
269+
0 => {
270+
// In this case we haven't changed, but wish to make a change.
271+
true
271272
}
272-
if !changed {
273-
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
274-
self.selcx.infcx()
275-
.resolve_vars_if_possible(&pending_obligation.obligation),
276-
pending_obligation.stalled_on);
277-
return ProcessResult::Unchanged;
273+
_ => {
274+
// This `for` loop was once a call to `all()`, but this lower-level
275+
// form was a perf win. See #64545 for details.
276+
(|| {
277+
for &ty in &pending_obligation.stalled_on {
278+
if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
279+
return true;
280+
}
281+
}
282+
false
283+
})()
278284
}
279-
pending_obligation.stalled_on = vec![];
285+
};
286+
287+
if !change {
288+
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
289+
self.selcx.infcx()
290+
.resolve_vars_if_possible(&pending_obligation.obligation),
291+
pending_obligation.stalled_on);
292+
return ProcessResult::Unchanged;
280293
}
281294

295+
// This part of the code is much colder.
296+
297+
pending_obligation.stalled_on.truncate(0);
298+
282299
let obligation = &mut pending_obligation.obligation;
283300

284301
if obligation.predicate.has_infer_types() {

0 commit comments

Comments
 (0)