]> git.lizzy.rs Git - rust.git/commitdiff
Specialize the `stalled_on` handling in `process_obligation()`.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 18 Sep 2019 04:50:48 +0000 (14:50 +1000)
committerNicholas Nethercote <nnethercote@mozilla.com>
Thu, 19 Sep 2019 23:51:52 +0000 (09:51 +1000)
Optimizing for the common numbers of entries in `stalled_on` wins about
4% on `keccak` and `inflate`.

src/librustc/infer/mod.rs
src/librustc/traits/fulfill.rs

index c5712cc9941a9d84d32dae63876a813360716607..eaef2198e3bcf3836925b43778313b6998765abd 100644 (file)
@@ -1600,8 +1600,8 @@ pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
 
     // `resolver.shallow_resolve_changed(ty)` is equivalent to
     // `resolver.shallow_resolve(ty) != ty`, but more efficient. It's always
-    // inlined, despite being large, because it has a single call site that is
-    // extremely hot.
+    // inlined, despite being large, because it has only two call sites that
+    // are extremely hot.
     #[inline(always)]
     pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
         match typ.sty {
index 805727b6ce0d72c0711065f284f07d2bf9af9d30..6c421e9df6800aad9c2a69d00a92c51ad559cf2c 100644 (file)
@@ -256,29 +256,46 @@ fn process_obligation(
         &mut self,
         pending_obligation: &mut Self::Obligation,
     ) -> ProcessResult<Self::Obligation, Self::Error> {
-        // 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 yet
-        if !pending_obligation.stalled_on.is_empty() {
-            let mut changed = false;
-            // This `for` loop was once a call to `all()`, but this lower-level
-            // form was a perf win. See #64545 for details.
-            for &ty in &pending_obligation.stalled_on {
-                if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
-                    changed = true;
-                    break;
-                }
+        // 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
+        // yet.
+        let change = match pending_obligation.stalled_on.len() {
+            // Match arms are in order of frequency, which matters because this
+            // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
+            1 => {
+                let ty = pending_obligation.stalled_on[0];
+                ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty)
+            }
+            0 => {
+                // In this case we haven't changed, but wish to make a change.
+                true
             }
-            if !changed {
-                debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
-                       self.selcx.infcx()
-                           .resolve_vars_if_possible(&pending_obligation.obligation),
-                       pending_obligation.stalled_on);
-                return ProcessResult::Unchanged;
+            _ => {
+                // This `for` loop was once a call to `all()`, but this lower-level
+                // form was a perf win. See #64545 for details.
+                (|| {
+                    for &ty in &pending_obligation.stalled_on {
+                        if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) {
+                            return true;
+                        }
+                    }
+                    false
+                })()
             }
-            pending_obligation.stalled_on = vec![];
+        };
+
+        if !change {
+            debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
+                   self.selcx.infcx()
+                       .resolve_vars_if_possible(&pending_obligation.obligation),
+                   pending_obligation.stalled_on);
+            return ProcessResult::Unchanged;
         }
 
+        // This part of the code is much colder.
+
+        pending_obligation.stalled_on.truncate(0);
+
         let obligation = &mut pending_obligation.obligation;
 
         if obligation.predicate.has_infer_types() {