Skip to content

[perf] cache type info for ParamEnv #123058

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions compiler/rustc_hir_analysis/src/collect/item_bounds.rs
Original file line number Diff line number Diff line change
@@ -165,10 +165,7 @@ pub(super) fn explicit_item_bounds_with_filter(
ty::EarlyBinder::bind(bounds)
}

pub(super) fn item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<ty::Clauses<'_>> {
tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
tcx.mk_clauses_from_iter(util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)))
})
@@ -177,7 +174,7 @@ pub(super) fn item_bounds(
pub(super) fn item_super_predicates(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
) -> ty::EarlyBinder<ty::Clauses<'_>> {
tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
tcx.mk_clauses_from_iter(
util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
@@ -188,12 +185,12 @@ pub(super) fn item_super_predicates(
pub(super) fn item_non_self_assumptions(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Clause<'_>>> {
) -> ty::EarlyBinder<ty::Clauses<'_>> {
let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
let own_bounds: FxIndexSet<_> =
tcx.item_super_predicates(def_id).skip_binder().iter().collect();
if all_bounds.len() == own_bounds.len() {
ty::EarlyBinder::bind(ty::List::empty())
ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty())
} else {
ty::EarlyBinder::bind(tcx.mk_clauses_from_iter(all_bounds.difference(&own_bounds).copied()))
}
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/query/erase.rs
Original file line number Diff line number Diff line change
@@ -67,6 +67,10 @@ impl<T> EraseType for &'_ ty::List<T> {
type Result = [u8; size_of::<&'static ty::List<()>>()];
}

impl<T> EraseType for &'_ ty::ListWithCachedTypeInfo<T> {
type Result = [u8; size_of::<&'static ty::ListWithCachedTypeInfo<()>>()];
}

impl<I: rustc_index::Idx, T> EraseType for &'_ rustc_index::IndexSlice<I, T> {
type Result = [u8; size_of::<&'static rustc_index::IndexSlice<u32, ()>>()];
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/query/keys.rs
Original file line number Diff line number Diff line change
@@ -432,7 +432,7 @@ impl<'tcx> Key for (Ty<'tcx>, Ty<'tcx>) {
}
}

impl<'tcx> Key for &'tcx ty::List<ty::Clause<'tcx>> {
impl<'tcx> Key for ty::Clauses<'tcx> {
type Cache<V> = DefaultCache<Self, V>;

fn default_span(&self, _: TyCtxt<'_>) -> Span {
8 changes: 4 additions & 4 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
@@ -398,15 +398,15 @@ rustc_queries! {
/// ```
///
/// Bounds from the parent (e.g. with nested impl trait) are not included.
query item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
query item_bounds(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
}

query item_super_predicates(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
query item_super_predicates(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
}

query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<&'tcx ty::List<ty::Clause<'tcx>>> {
query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<ty::Clauses<'tcx>> {
desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
}

@@ -2156,7 +2156,7 @@ rustc_queries! {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
}

query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Clause<'tcx>>) -> &'tcx ty::List<ty::Clause<'tcx>> {
query reveal_opaque_types_in_bounds(key: ty::Clauses<'tcx>) -> ty::Clauses<'tcx> {
desc { "revealing opaque types in `{:?}`", key }
}

6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/ty/codec.rs
Original file line number Diff line number Diff line change
@@ -414,7 +414,9 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
}
}

impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty::Clause<'tcx>> {
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D>
for ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>
{
fn decode(decoder: &mut D) -> &'tcx Self {
let len = decoder.read_usize();
decoder.interner().mk_clauses_from_iter(
@@ -461,7 +463,7 @@ impl_decodable_via_ref! {
&'tcx mir::BorrowCheckResult<'tcx>,
&'tcx mir::coverage::CodeRegion,
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Clause<'tcx>>,
&'tcx ty::ListWithCachedTypeInfo<ty::Clause<'tcx>>,
&'tcx ty::List<FieldIdx>,
&'tcx ty::List<(VariantIdx, FieldIdx)>,
}
61 changes: 51 additions & 10 deletions compiler/rustc_middle/src/ty/context.rs
Original file line number Diff line number Diff line change
@@ -25,10 +25,10 @@ use crate::traits::solve::{
ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
};
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Const, ConstData, GenericParamDefKind,
ImplPolarity, List, ParamConst, ParamTy, PolyExistentialPredicate, PolyFnSig, Predicate,
PredicateKind, PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty,
TyKind, TyVid, TypeVisitable, Visibility,
self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, Region,
RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable, Visibility,
};
use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
use rustc_ast::{self as ast, attr};
@@ -130,6 +130,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
type SubtypePredicate = ty::SubtypePredicate<'tcx>;
type CoercePredicate = ty::CoercePredicate<'tcx>;
type ClosureKind = ty::ClosureKind;
type Clauses = ty::Clauses<'tcx>;

fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
self.mk_canonical_var_infos(infos)
@@ -152,7 +153,7 @@ pub struct CtxtInterners<'tcx> {
region: InternedSet<'tcx, RegionKind<'tcx>>,
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
predicate: InternedSet<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
clauses: InternedSet<'tcx, List<Clause<'tcx>>>,
clauses: InternedSet<'tcx, ListWithCachedTypeInfo<Clause<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
const_: InternedSet<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>,
@@ -286,6 +287,24 @@ impl<'tcx> CtxtInterners<'tcx> {
.0,
))
}

fn intern_clauses(&self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
if clauses.is_empty() {
ListWithCachedTypeInfo::empty()
} else {
self.clauses
.intern_ref(clauses, || {
let flags = super::flags::FlagComputation::for_clauses(clauses);

InternedInSet(ListWithCachedTypeInfo::from_arena(
&*self.arena,
flags.into(),
clauses,
))
})
.0
}
}
}

// For these preinterned values, an alternative would be to have
@@ -1775,6 +1794,29 @@ impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, List<T>> {
}
}

impl<'tcx, T> Borrow<[T]> for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
fn borrow(&self) -> &[T] {
&self.0[..]
}
}

impl<'tcx, T: PartialEq> PartialEq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
fn eq(&self, other: &InternedInSet<'tcx, ListWithCachedTypeInfo<T>>) -> bool {
// The `Borrow` trait requires that `x.borrow() == y.borrow()` equals
// `x == y`.
self.0[..] == other.0[..]
}
}

impl<'tcx, T: Eq> Eq for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {}

impl<'tcx, T: Hash> Hash for InternedInSet<'tcx, ListWithCachedTypeInfo<T>> {
fn hash<H: Hasher>(&self, s: &mut H) {
// The `Borrow` trait requires that `x.borrow().hash(s) == x.hash(s)`.
self.0[..].hash(s)
}
}

macro_rules! direct_interners {
($($name:ident: $vis:vis $method:ident($ty:ty): $ret_ctor:ident -> $ret_ty:ty,)+) => {
$(impl<'tcx> Borrow<$ty> for InternedInSet<'tcx, $ty> {
@@ -1833,7 +1875,7 @@ macro_rules! slice_interners {
List::empty()
} else {
self.interners.$field.intern_ref(v, || {
InternedInSet(List::from_arena(&*self.arena, v))
InternedInSet(List::from_arena(&*self.arena, (), v))
}).0
}
})+
@@ -1850,7 +1892,6 @@ slice_interners!(
type_lists: pub mk_type_list(Ty<'tcx>),
canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
clauses: intern_clauses(Clause<'tcx>),
projs: pub mk_projs(ProjectionKind),
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
@@ -2155,11 +2196,11 @@ impl<'tcx> TyCtxt<'tcx> {
self.intern_poly_existential_predicates(eps)
}

pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> &'tcx List<Clause<'tcx>> {
pub fn mk_clauses(self, clauses: &[Clause<'tcx>]) -> Clauses<'tcx> {
// FIXME consider asking the input slice to be sorted to avoid
// re-interning permutations, in which case that would be asserted
// here.
self.intern_clauses(clauses)
self.interners.intern_clauses(clauses)
}

pub fn mk_local_def_ids(self, clauses: &[LocalDefId]) -> &'tcx List<LocalDefId> {
@@ -2223,7 +2264,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn mk_clauses_from_iter<I, T>(self, iter: I) -> T::Output
where
I: Iterator<Item = T>,
T: CollectAndApply<Clause<'tcx>, &'tcx List<Clause<'tcx>>>,
T: CollectAndApply<Clause<'tcx>, Clauses<'tcx>>,
{
T::collect_and_apply(iter, |xs| self.mk_clauses(xs))
}
9 changes: 9 additions & 0 deletions compiler/rustc_middle/src/ty/flags.rs
Original file line number Diff line number Diff line change
@@ -35,6 +35,15 @@ impl FlagComputation {
result
}

pub fn for_clauses(clauses: &[ty::Clause<'_>]) -> FlagComputation {
let mut result = FlagComputation::new();
for c in clauses {
result.add_flags(c.as_predicate().flags());
result.add_exclusive_binder(c.as_predicate().outer_exclusive_binder());
}
result
}

fn add_flags(&mut self, flags: TypeFlags) {
self.flags = self.flags | flags;
}
9 changes: 5 additions & 4 deletions compiler/rustc_middle/src/ty/impls_ty.rs
Original file line number Diff line number Diff line change
@@ -11,19 +11,20 @@ use rustc_data_structures::stable_hasher::HashingControls;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
use rustc_query_system::ich::StableHashingContext;
use std::cell::RefCell;
use std::ptr;

impl<'a, 'tcx, T> HashStable<StableHashingContext<'a>> for &'tcx ty::List<T>
impl<'a, 'tcx, H, T> HashStable<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T>
where
T: HashStable<StableHashingContext<'a>>,
{
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
thread_local! {
static CACHE: RefCell<FxHashMap<(usize, usize, HashingControls), Fingerprint>> =
static CACHE: RefCell<FxHashMap<(*const (), HashingControls), Fingerprint>> =
RefCell::new(Default::default());
}

let hash = CACHE.with(|cache| {
let key = (self.as_ptr() as usize, self.len(), hcx.hashing_controls());
let key = (ptr::from_ref(*self).cast::<()>(), hcx.hashing_controls());
if let Some(&hash) = cache.borrow().get(&key) {
return hash;
}
@@ -40,7 +41,7 @@ where
}
}

impl<'a, 'tcx, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::List<T>
impl<'a, 'tcx, H, T> ToStableHashKey<StableHashingContext<'a>> for &'tcx ty::list::RawList<H, T>
where
T: HashStable<StableHashingContext<'a>>,
{
Loading