Improve comments in `needs_process_obligation`.

And a couple of other places.
This commit is contained in:
Nicholas Nethercote 2023-03-03 09:23:07 +11:00
parent ca1bc7f1f6
commit 3bcea5f979
2 changed files with 34 additions and 24 deletions

View File

@ -426,6 +426,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// nodes. Therefore we use a `while` loop. // nodes. Therefore we use a `while` loop.
let mut index = 0; let mut index = 0;
while let Some(node) = self.nodes.get_mut(index) { while let Some(node) = self.nodes.get_mut(index) {
// This test is extremely hot.
if node.state.get() != NodeState::Pending if node.state.get() != NodeState::Pending
|| !processor.needs_process_obligation(&node.obligation) || !processor.needs_process_obligation(&node.obligation)
{ {
@ -439,6 +440,7 @@ impl<O: ForestObligation> ObligationForest<O> {
// out of sync with `nodes`. It's not very common, but it does // out of sync with `nodes`. It's not very common, but it does
// happen, and code in `compress` has to allow for it. // happen, and code in `compress` has to allow for it.
// This code is much less hot.
match processor.process_obligation(&mut node.obligation) { match processor.process_obligation(&mut node.obligation) {
ProcessResult::Unchanged => { ProcessResult::Unchanged => {
// No change in state. // No change in state.

View File

@ -212,36 +212,44 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
/// Identifies whether a predicate obligation needs processing. /// Identifies whether a predicate obligation needs processing.
/// ///
/// This is always inlined, despite its size, because it has a single /// This is always inlined because it has a single callsite and it is
/// callsite and it is called *very* frequently. /// called *very* frequently. Be careful modifying this code! Several
/// compile-time benchmarks are very sensitive to even small changes.
#[inline(always)] #[inline(always)]
fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool { fn needs_process_obligation(&self, pending_obligation: &Self::Obligation) -> bool {
// If we were stalled on some unresolved variables, first check whether // If we were stalled on some unresolved variables, first check whether
// any of them have been resolved; if not, don't bother doing more work // any of them have been resolved; if not, don't bother doing more work
// yet. // yet.
match pending_obligation.stalled_on.len() { let stalled_on = &pending_obligation.stalled_on;
// Match arms are in order of frequency, which matters because this match stalled_on.len() {
// code is so hot. 1 and 0 dominate; 2+ is fairly rare. // This case is the hottest most of the time, being hit up to 99%
1 => { // of the time. `keccak` and `cranelift-codegen-0.82.1` are
let infer_var = pending_obligation.stalled_on[0]; // benchmarks that particularly stress this path.
self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) 1 => self.selcx.infcx.ty_or_const_infer_var_changed(stalled_on[0]),
}
0 => { // In this case we haven't changed, but wish to make a change. Note
// In this case we haven't changed, but wish to make a change. // that this is a special case, and is not equivalent to the `_`
true // case below, which would return `false` for an empty `stalled_on`
} // vector.
_ => { //
// This `for` loop was once a call to `all()`, but this lower-level // This case is usually hit only 1% of the time or less, though it
// form was a perf win. See #64545 for details. // reaches 20% in `wasmparser-0.101.0`.
(|| { 0 => true,
for &infer_var in &pending_obligation.stalled_on {
if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) { // This case is usually hit only 1% of the time or less, though it
return true; // reaches 95% in `mime-0.3.16`, 64% in `wast-54.0.0`, and 12% in
} // `inflate-0.4.5`.
//
// The obvious way of writing this, with a call to `any()` and no
// closure, is currently slower than this version.
_ => (|| {
for &infer_var in stalled_on {
if self.selcx.infcx.ty_or_const_infer_var_changed(infer_var) {
return true;
} }
false }
})() false
} })(),
} }
} }