Skip to content

Commit

Permalink
Auto merge of rust-lang#64545 - nnethercote:ObligForest-more, r=nmats…
Browse files Browse the repository at this point in the history
…akis

More `ObligationForest` improvements

Following on from rust-lang#64500, these commits alsomake the code both nicer and faster.

r? @nikomatsakis
  • Loading branch information
bors committed Sep 19, 2019
2 parents 19d0703 + 3b85597 commit 9b9d2af
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 118 deletions.
44 changes: 38 additions & 6 deletions src/librustc/infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1562,11 +1562,7 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
ShallowResolver { infcx }
}

// We have this force-inlined variant of `shallow_resolve` for the one
// callsite that is extremely hot. All other callsites use the normal
// variant.
#[inline(always)]
pub fn inlined_shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
pub fn shallow_resolve(&mut self, typ: Ty<'tcx>) -> Ty<'tcx> {
match typ.sty {
ty::Infer(ty::TyVar(v)) => {
// Not entirely obvious: if `typ` is a type variable,
Expand Down Expand Up @@ -1601,6 +1597,42 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
_ => typ,
}
}

// `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.
#[inline(always)]
pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool {
match typ.sty {
ty::Infer(ty::TyVar(v)) => {
use self::type_variable::TypeVariableValue;

// See the comment in `shallow_resolve()`.
match self.infcx.type_variables.borrow_mut().probe(v) {
TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ,
TypeVariableValue::Unknown { .. } => false,
}
}

ty::Infer(ty::IntVar(v)) => {
match self.infcx.int_unification_table.borrow_mut().probe_value(v) {
Some(v) => v.to_type(self.infcx.tcx) != typ,
None => false,
}
}

ty::Infer(ty::FloatVar(v)) => {
match self.infcx.float_unification_table.borrow_mut().probe_value(v) {
Some(v) => v.to_type(self.infcx.tcx) != typ,
None => false,
}
}

_ => false,
}
}

}

impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
Expand All @@ -1609,7 +1641,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {
}

fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
self.inlined_shallow_resolve(ty)
self.shallow_resolve(ty)
}

fn fold_const(&mut self, ct: &'tcx ty::Const<'tcx>) -> &'tcx ty::Const<'tcx> {
Expand Down
17 changes: 11 additions & 6 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,15 +256,20 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
&mut self,
pending_obligation: &mut Self::Obligation,
) -> ProcessResult<Self::Obligation, Self::Error> {
// if we were stalled on some unresolved variables, first check
// 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() {
if pending_obligation.stalled_on.iter().all(|&ty| {
// Use the force-inlined variant of shallow_resolve() because this code is hot.
let resolved = ShallowResolver::new(self.selcx.infcx()).inlined_shallow_resolve(ty);
resolved == ty // nothing changed here
}) {
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 !changed {
debug!("process_predicate: pending obligation {:?} still stalled on {:?}",
self.selcx.infcx()
.resolve_vars_if_possible(&pending_obligation.obligation),
Expand Down
4 changes: 1 addition & 3 deletions src/librustc_data_structures/obligation_forest/graphviz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,7 @@ impl<'a, O: ForestObligation + 'a> dot::GraphWalk<'a> for &'a ObligationForest<O
.flat_map(|i| {
let node = &self.nodes[i];

node.parent.iter()
.chain(node.dependents.iter())
.map(move |p| (p.index(), i))
node.dependents.iter().map(move |&d| (d, i))
})
.collect()
}
Expand Down
Loading

0 comments on commit 9b9d2af

Please sign in to comment.