1
Fork 0

Auto merge of #67079 - nnethercote:optimize-shallow_resolve_changed, r=nikomatsakis

Optimize `shallow_resolve_changed`

r? @nikomatsakis
This commit is contained in:
bors 2019-12-12 11:51:26 +00:00
commit 3eebe058e5
2 changed files with 36 additions and 28 deletions

View file

@ -1618,37 +1618,37 @@ impl<'a, 'tcx> ShallowResolver<'a, 'tcx> {
// inlined, despite being large, because it has only two call sites that // inlined, despite being large, because it has only two call sites that
// are extremely hot. // are extremely hot.
#[inline(always)] #[inline(always)]
pub fn shallow_resolve_changed(&mut self, typ: Ty<'tcx>) -> bool { pub fn shallow_resolve_changed(&self, infer: ty::InferTy) -> bool {
match typ.kind { match infer {
ty::Infer(ty::TyVar(v)) => { ty::TyVar(v) => {
use self::type_variable::TypeVariableValue; use self::type_variable::TypeVariableValue;
// See the comment in `shallow_resolve()`. // If `inlined_probe` returns a `Known` value its `kind` never
// matches `infer`.
match self.infcx.type_variables.borrow_mut().inlined_probe(v) { match self.infcx.type_variables.borrow_mut().inlined_probe(v) {
TypeVariableValue::Known { value: t } => self.fold_ty(t) != typ,
TypeVariableValue::Unknown { .. } => false, TypeVariableValue::Unknown { .. } => false,
TypeVariableValue::Known { .. } => true,
} }
} }
ty::Infer(ty::IntVar(v)) => { ty::IntVar(v) => {
match self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v) { // If inlined_probe_value returns a value it's always a
Some(v) => v.to_type(self.infcx.tcx) != typ, // `ty::Int(_)` or `ty::UInt(_)`, which nevers matches a
None => false, // `ty::Infer(_)`.
} self.infcx.int_unification_table.borrow_mut().inlined_probe_value(v).is_some()
} }
ty::Infer(ty::FloatVar(v)) => { ty::FloatVar(v) => {
// If inlined_probe_value returns a value it's always a
// `ty::Float(_)`, which nevers matches a `ty::Infer(_)`.
//
// Not `inlined_probe_value(v)` because this call site is colder. // Not `inlined_probe_value(v)` because this call site is colder.
match self.infcx.float_unification_table.borrow_mut().probe_value(v) { self.infcx.float_unification_table.borrow_mut().probe_value(v).is_some()
Some(v) => v.to_type(self.infcx.tcx) != typ,
None => false,
}
} }
_ => false, _ => unreachable!(),
} }
} }
} }
impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> { impl<'a, 'tcx> TypeFolder<'tcx> for ShallowResolver<'a, 'tcx> {

View file

@ -65,7 +65,7 @@ pub struct FulfillmentContext<'tcx> {
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct PendingPredicateObligation<'tcx> { pub struct PendingPredicateObligation<'tcx> {
pub obligation: PredicateObligation<'tcx>, pub obligation: PredicateObligation<'tcx>,
pub stalled_on: Vec<Ty<'tcx>>, pub stalled_on: Vec<ty::InferTy>,
} }
// `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger.
@ -263,8 +263,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
// Match arms are in order of frequency, which matters because this // Match arms are in order of frequency, which matters because this
// code is so hot. 1 and 0 dominate; 2+ is fairly rare. // code is so hot. 1 and 0 dominate; 2+ is fairly rare.
1 => { 1 => {
let ty = pending_obligation.stalled_on[0]; let infer = pending_obligation.stalled_on[0];
ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer)
} }
0 => { 0 => {
// In this case we haven't changed, but wish to make a change. // In this case we haven't changed, but wish to make a change.
@ -274,8 +274,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
// This `for` loop was once a call to `all()`, but this lower-level // This `for` loop was once a call to `all()`, but this lower-level
// form was a perf win. See #64545 for details. // form was a perf win. See #64545 for details.
(|| { (|| {
for &ty in &pending_obligation.stalled_on { for &infer in &pending_obligation.stalled_on {
if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(ty) { if ShallowResolver::new(self.selcx.infcx()).shallow_resolve_changed(infer) {
return true; return true;
} }
} }
@ -305,6 +305,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause); debug!("process_obligation: obligation = {:?} cause = {:?}", obligation, obligation.cause);
fn infer_ty(ty: Ty<'tcx>) -> ty::InferTy {
match ty.kind {
ty::Infer(infer) => infer,
_ => panic!(),
}
}
match obligation.predicate { match obligation.predicate {
ty::Predicate::Trait(ref data) => { ty::Predicate::Trait(ref data) => {
let trait_obligation = obligation.with(data.clone()); let trait_obligation = obligation.with(data.clone());
@ -459,7 +466,7 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
obligation.cause.span, obligation.cause.span,
) { ) {
None => { None => {
pending_obligation.stalled_on = vec![ty]; pending_obligation.stalled_on = vec![infer_ty(ty)];
ProcessResult::Unchanged ProcessResult::Unchanged
} }
Some(os) => ProcessResult::Changed(mk_pending(os)) Some(os) => ProcessResult::Changed(mk_pending(os))
@ -472,8 +479,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
subtype) { subtype) {
None => { None => {
// None means that both are unresolved. // None means that both are unresolved.
pending_obligation.stalled_on = vec![subtype.skip_binder().a, pending_obligation.stalled_on = vec![infer_ty(subtype.skip_binder().a),
subtype.skip_binder().b]; infer_ty(subtype.skip_binder().b)];
ProcessResult::Unchanged ProcessResult::Unchanged
} }
Some(Ok(ok)) => { Some(Ok(ok)) => {
@ -517,7 +524,8 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
)) ))
} }
} else { } else {
pending_obligation.stalled_on = substs.types().collect(); pending_obligation.stalled_on =
substs.types().map(|ty| infer_ty(ty)).collect();
ProcessResult::Unchanged ProcessResult::Unchanged
} }
} }
@ -542,13 +550,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
fn trait_ref_type_vars<'a, 'tcx>( fn trait_ref_type_vars<'a, 'tcx>(
selcx: &mut SelectionContext<'a, 'tcx>, selcx: &mut SelectionContext<'a, 'tcx>,
t: ty::PolyTraitRef<'tcx>, t: ty::PolyTraitRef<'tcx>,
) -> Vec<Ty<'tcx>> { ) -> Vec<ty::InferTy> {
t.skip_binder() // ok b/c this check doesn't care about regions t.skip_binder() // ok b/c this check doesn't care about regions
.input_types() .input_types()
.map(|t| selcx.infcx().resolve_vars_if_possible(&t)) .map(|t| selcx.infcx().resolve_vars_if_possible(&t))
.filter(|t| t.has_infer_types()) .filter(|t| t.has_infer_types())
.flat_map(|t| t.walk()) .flat_map(|t| t.walk())
.filter(|t| match t.kind { ty::Infer(_) => true, _ => false }) .filter_map(|t| match t.kind { ty::Infer(infer) => Some(infer), _ => None })
.collect() .collect()
} }