Fast path that skips over unchanged obligations in process_obligations

- only borrow the refcell once per loop
- avoid complex matches to reduce branch paths in the hot loop
- use a by-ref fast path that avoids mutations at the expense of having false negatives
This commit is contained in:
The 8472 2023-03-06 15:07:02 +01:00
parent 03b01c5bec
commit 7cce618d18
6 changed files with 79 additions and 6 deletions

View file

@ -211,6 +211,29 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
type Error = FulfillmentErrorCode<'tcx>;
type OUT = Outcome<Self::Obligation, Self::Error>;
/// Compared to `needs_process_obligation` this and its callees
/// contain some optimizations that come at the price of false negatives.
///
/// They
/// - reduce branching by covering only the most common case
/// - take a read-only view of the unification tables which allows skipping undo_log
/// construction.
/// - bail out on value-cache misses in ena to avoid pointer chasing
/// - hoist RefCell locking out of the loop
#[inline]
fn skippable_obligations<'b>(
&'b self,
it: impl Iterator<Item = &'b Self::Obligation>,
) -> usize {
let is_unchanged = self.selcx.infcx.is_ty_infer_var_definitely_unchanged();
it.take_while(|o| match o.stalled_on.as_slice() {
[o] => is_unchanged(*o),
_ => false,
})
.count()
}
/// Identifies whether a predicate obligation needs processing.
///
/// This is always inlined because it has a single callsite and it is