Auto merge of #94487 - oli-obk:stable_hash_ty, r=fee1-dead

Also cache the stable hash of interned Predicates

continuation of https://github.com/rust-lang/rust/pull/94299

This is a small perf improvement and shares more code between `Ty` and `Predicate`
This commit is contained in:
bors 2022-11-29 21:35:02 +00:00
commit bddad597fe
3 changed files with 59 additions and 28 deletions

View File

@ -89,7 +89,7 @@ macro_rules! arena_types {
// Interned types // Interned types
[] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>, [] tys: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::TyS<'tcx>>,
[] predicates: rustc_middle::ty::PredicateS<'tcx>, [] predicates: rustc_data_structures::intern::WithStableHash<rustc_middle::ty::PredicateS<'tcx>>,
[] consts: rustc_middle::ty::ConstS<'tcx>, [] consts: rustc_middle::ty::ConstS<'tcx>,
// Note that this deliberately duplicates items in the `rustc_hir::arena`, // Note that this deliberately duplicates items in the `rustc_hir::arena`,

View File

@ -142,7 +142,7 @@ pub struct CtxtInterners<'tcx> {
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>, canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
region: InternedSet<'tcx, RegionKind<'tcx>>, region: InternedSet<'tcx, RegionKind<'tcx>>,
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>, poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
predicate: InternedSet<'tcx, PredicateS<'tcx>>, predicate: InternedSet<'tcx, WithStableHash<PredicateS<'tcx>>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>, predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>, projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>, place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
@ -190,20 +190,8 @@ impl<'tcx> CtxtInterners<'tcx> {
self.type_ self.type_
.intern(kind, |kind| { .intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_kind(&kind); let flags = super::flags::FlagComputation::for_kind(&kind);
let stable_hash =
// It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them. self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
// Without incremental, we rarely stable-hash types, so let's not do it proactively.
let stable_hash = if flags.flags.intersects(TypeFlags::NEEDS_INFER)
|| sess.opts.incremental.is_none()
{
Fingerprint::ZERO
} else {
let mut hasher = StableHasher::new();
let mut hcx =
StableHashingContext::new(sess, definitions, cstore, source_span);
kind.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
};
let ty_struct = TyS { let ty_struct = TyS {
kind, kind,
@ -219,20 +207,54 @@ impl<'tcx> CtxtInterners<'tcx> {
)) ))
} }
fn stable_hash<'a, T: HashStable<StableHashingContext<'a>>>(
&self,
flags: &ty::flags::FlagComputation,
sess: &'a Session,
definitions: &'a rustc_hir::definitions::Definitions,
cstore: &'a CrateStoreDyn,
source_span: &'a IndexVec<LocalDefId, Span>,
val: &T,
) -> Fingerprint {
// It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
// Without incremental, we rarely stable-hash types, so let's not do it proactively.
if flags.flags.intersects(TypeFlags::NEEDS_INFER) || sess.opts.incremental.is_none() {
Fingerprint::ZERO
} else {
let mut hasher = StableHasher::new();
let mut hcx = StableHashingContext::new(sess, definitions, cstore, source_span);
val.hash_stable(&mut hcx, &mut hasher);
hasher.finish()
}
}
#[inline(never)] #[inline(never)]
fn intern_predicate(&self, kind: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { fn intern_predicate(
&self,
kind: Binder<'tcx, PredicateKind<'tcx>>,
sess: &Session,
definitions: &rustc_hir::definitions::Definitions,
cstore: &CrateStoreDyn,
source_span: &IndexVec<LocalDefId, Span>,
) -> Predicate<'tcx> {
Predicate(Interned::new_unchecked( Predicate(Interned::new_unchecked(
self.predicate self.predicate
.intern(kind, |kind| { .intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_predicate(kind); let flags = super::flags::FlagComputation::for_predicate(kind);
let stable_hash =
self.stable_hash(&flags, sess, definitions, cstore, source_span, &kind);
let predicate_struct = PredicateS { let predicate_struct = PredicateS {
kind, kind,
flags: flags.flags, flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder, outer_exclusive_binder: flags.outer_exclusive_binder,
}; };
InternedInSet(self.arena.alloc(predicate_struct)) InternedInSet(
self.arena
.alloc(WithStableHash { internee: predicate_struct, stable_hash }),
)
}) })
.0, .0,
)) ))
@ -2168,23 +2190,25 @@ impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<TyS<'tcx>>> {
} }
} }
impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>> for InternedInSet<'tcx, PredicateS<'tcx>> { impl<'tcx> Borrow<Binder<'tcx, PredicateKind<'tcx>>>
for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>
{
fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> { fn borrow<'a>(&'a self) -> &'a Binder<'tcx, PredicateKind<'tcx>> {
&self.0.kind &self.0.kind
} }
} }
impl<'tcx> PartialEq for InternedInSet<'tcx, PredicateS<'tcx>> { impl<'tcx> PartialEq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
fn eq(&self, other: &InternedInSet<'tcx, PredicateS<'tcx>>) -> bool { fn eq(&self, other: &InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>>) -> bool {
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals // The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
// `x == y`. // `x == y`.
self.0.kind == other.0.kind self.0.kind == other.0.kind
} }
} }
impl<'tcx> Eq for InternedInSet<'tcx, PredicateS<'tcx>> {} impl<'tcx> Eq for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {}
impl<'tcx> Hash for InternedInSet<'tcx, PredicateS<'tcx>> { impl<'tcx> Hash for InternedInSet<'tcx, WithStableHash<PredicateS<'tcx>>> {
fn hash<H: Hasher>(&self, s: &mut H) { fn hash<H: Hasher>(&self, s: &mut H) {
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`. // The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0.kind.hash(s) self.0.kind.hash(s)
@ -2386,7 +2410,14 @@ impl<'tcx> TyCtxt<'tcx> {
#[inline] #[inline]
pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> { pub fn mk_predicate(self, binder: Binder<'tcx, PredicateKind<'tcx>>) -> Predicate<'tcx> {
self.interners.intern_predicate(binder) self.interners.intern_predicate(
binder,
self.sess,
&self.definitions.read(),
&*self.untracked_resolutions.cstore,
// This is only used to create a stable hashing context.
&self.untracked_resolutions.source_span,
)
} }
#[inline] #[inline]

View File

@ -548,9 +548,9 @@ pub(crate) struct PredicateS<'tcx> {
} }
/// Use this rather than `PredicateS`, whenever possible. /// Use this rather than `PredicateS`, whenever possible.
#[derive(Clone, Copy, PartialEq, Eq, Hash)] #[derive(Clone, Copy, PartialEq, Eq, Hash, HashStable)]
#[rustc_pass_by_value] #[rustc_pass_by_value]
pub struct Predicate<'tcx>(Interned<'tcx, PredicateS<'tcx>>); pub struct Predicate<'tcx>(Interned<'tcx, WithStableHash<PredicateS<'tcx>>>);
impl<'tcx> Predicate<'tcx> { impl<'tcx> Predicate<'tcx> {
/// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`. /// Gets the inner `Binder<'tcx, PredicateKind<'tcx>>`.
@ -631,7 +631,7 @@ impl<'tcx> Predicate<'tcx> {
} }
} }
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for PredicateS<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let PredicateS { let PredicateS {
ref kind, ref kind,
@ -640,7 +640,7 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
// also contained in `kind`, so no need to hash them. // also contained in `kind`, so no need to hash them.
flags: _, flags: _,
outer_exclusive_binder: _, outer_exclusive_binder: _,
} = self.0.0; } = self;
kind.hash_stable(hcx, hasher); kind.hash_stable(hcx, hasher);
} }