Skip to content

Commit

Permalink
Cache flags and escaping vars for predicates
Browse files Browse the repository at this point in the history
Also hash predicates by address
  • Loading branch information
matthewjasper committed Jun 21, 2020
1 parent 8ea55f1 commit f802ee1
Show file tree
Hide file tree
Showing 6 changed files with 202 additions and 28 deletions.
1 change: 1 addition & 0 deletions src/librustc_middle/arena.rs
Expand Up @@ -100,6 +100,7 @@ macro_rules! arena_types {

// Interned types
[] tys: rustc_middle::ty::TyS<$tcx>, rustc_middle::ty::TyS<'_x>;
[] predicates: rustc_middle::ty::PredicateInner<$tcx>, rustc_middle::ty::PredicateInner<'_x>;

// HIR query types
[few] indexed_hir: rustc_middle::hir::map::IndexedHir<$tcx>, rustc_middle::hir::map::IndexedHir<'_x>;
Expand Down
57 changes: 47 additions & 10 deletions src/librustc_middle/ty/context.rs
Expand Up @@ -19,8 +19,9 @@ use crate::ty::TyKind::*;
use crate::ty::{
self, query, AdtDef, AdtKind, BindingMode, BoundVar, CanonicalPolyFnSig, Const, ConstVid,
DefIdTree, ExistentialPredicate, FloatVar, FloatVid, GenericParamDefKind, InferConst, InferTy,
IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateKind, ProjectionTy,
Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar, TyVid, TypeAndMut,
IntVar, IntVid, List, ParamConst, ParamTy, PolyFnSig, Predicate, PredicateInner, PredicateKind,
ProjectionTy, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyS, TyVar,
TyVid, TypeAndMut,
};
use rustc_ast::ast;
use rustc_ast::expand::allocator::AllocatorKind;
Expand Down Expand Up @@ -76,7 +77,7 @@ pub struct CtxtInterners<'tcx> {
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo>>,
region: InternedSet<'tcx, RegionKind>,
existential_predicates: InternedSet<'tcx, List<ExistentialPredicate<'tcx>>>,
predicate_kind: InternedSet<'tcx, PredicateKind<'tcx>>,
predicate: InternedSet<'tcx, PredicateInner<'tcx>>,
predicates: InternedSet<'tcx, List<Predicate<'tcx>>>,
projs: InternedSet<'tcx, List<ProjectionKind>>,
place_elems: InternedSet<'tcx, List<PlaceElem<'tcx>>>,
Expand All @@ -95,7 +96,7 @@ impl<'tcx> CtxtInterners<'tcx> {
region: Default::default(),
existential_predicates: Default::default(),
canonical_var_infos: Default::default(),
predicate_kind: Default::default(),
predicate: Default::default(),
predicates: Default::default(),
projs: Default::default(),
place_elems: Default::default(),
Expand Down Expand Up @@ -123,6 +124,23 @@ impl<'tcx> CtxtInterners<'tcx> {
})
.0
}

#[inline(never)]
fn intern_predicate(&self, kind: PredicateKind<'tcx>) -> &'tcx PredicateInner<'tcx> {
self.predicate
.intern(kind, |kind| {
let flags = super::flags::FlagComputation::for_predicate(&kind);

let predicate_struct = PredicateInner {
kind,
flags: flags.flags,
outer_exclusive_binder: flags.outer_exclusive_binder,
};

Interned(self.arena.alloc(predicate_struct))
})
.0
}
}

pub struct CommonTypes<'tcx> {
Expand Down Expand Up @@ -1627,7 +1645,7 @@ macro_rules! nop_list_lift {
nop_lift! {type_; Ty<'a> => Ty<'tcx>}
nop_lift! {region; Region<'a> => Region<'tcx>}
nop_lift! {const_; &'a Const<'a> => &'tcx Const<'tcx>}
nop_lift! {predicate_kind; &'a PredicateKind<'a> => &'tcx PredicateKind<'tcx>}
nop_lift! {predicate; &'a PredicateInner<'a> => &'tcx PredicateInner<'tcx>}

nop_list_lift! {type_list; Ty<'a> => Ty<'tcx>}
nop_list_lift! {existential_predicates; ExistentialPredicate<'a> => ExistentialPredicate<'tcx>}
Expand Down Expand Up @@ -1986,6 +2004,26 @@ impl<'tcx> Borrow<TyKind<'tcx>> for Interned<'tcx, TyS<'tcx>> {
&self.0.kind
}
}
// N.B., an `Interned<PredicateInner>` compares and hashes as a `PredicateKind`.
impl<'tcx> PartialEq for Interned<'tcx, PredicateInner<'tcx>> {
fn eq(&self, other: &Interned<'tcx, PredicateInner<'tcx>>) -> bool {
self.0.kind == other.0.kind
}
}

impl<'tcx> Eq for Interned<'tcx, PredicateInner<'tcx>> {}

impl<'tcx> Hash for Interned<'tcx, PredicateInner<'tcx>> {
fn hash<H: Hasher>(&self, s: &mut H) {
self.0.kind.hash(s)
}
}

impl<'tcx> Borrow<PredicateKind<'tcx>> for Interned<'tcx, PredicateInner<'tcx>> {
fn borrow<'a>(&'a self) -> &'a PredicateKind<'tcx> {
&self.0.kind
}
}

// N.B., an `Interned<List<T>>` compares and hashes as its elements.
impl<'tcx, T: PartialEq> PartialEq for Interned<'tcx, List<T>> {
Expand Down Expand Up @@ -2052,11 +2090,10 @@ macro_rules! direct_interners {
}
}

direct_interners!(
direct_interners! {
region: mk_region(RegionKind),
const_: mk_const(Const<'tcx>),
predicate_kind: intern_predicate_kind(PredicateKind<'tcx>),
);
}

macro_rules! slice_interners {
($($field:ident: $method:ident($ty:ty)),+) => (
Expand Down Expand Up @@ -2127,8 +2164,8 @@ impl<'tcx> TyCtxt<'tcx> {

#[inline]
pub fn mk_predicate(&self, kind: PredicateKind<'tcx>) -> Predicate<'tcx> {
let kind = self.intern_predicate_kind(kind);
Predicate { kind }
let inner = self.interners.intern_predicate(kind);
Predicate { inner }
}

pub fn mk_mach_int(self, tm: ast::IntTy) -> Ty<'tcx> {
Expand Down
82 changes: 73 additions & 9 deletions src/librustc_middle/ty/flags.rs
@@ -1,5 +1,6 @@
use crate::ty::subst::{GenericArg, GenericArgKind};
use crate::ty::{self, InferConst, Ty, TypeFlags};
use std::slice;

#[derive(Debug)]
pub struct FlagComputation {
Expand All @@ -21,6 +22,12 @@ impl FlagComputation {
result
}

pub fn for_predicate(kind: &ty::PredicateKind<'_>) -> FlagComputation {
let mut result = FlagComputation::new();
result.add_predicate_kind(kind);
result
}

pub fn for_const(c: &ty::Const<'_>) -> TypeFlags {
let mut result = FlagComputation::new();
result.add_const(c);
Expand All @@ -32,7 +39,7 @@ impl FlagComputation {
}

/// indicates that `self` refers to something at binding level `binder`
fn add_binder(&mut self, binder: ty::DebruijnIndex) {
fn add_bound_var(&mut self, binder: ty::DebruijnIndex) {
let exclusive_binder = binder.shifted_in(1);
self.add_exclusive_binder(exclusive_binder);
}
Expand All @@ -46,7 +53,7 @@ impl FlagComputation {

/// Adds the flags/depth from a set of types that appear within the current type, but within a
/// region binder.
fn add_bound_computation(&mut self, computation: &FlagComputation) {
fn add_bound_computation(&mut self, computation: FlagComputation) {
self.add_flags(computation.flags);

// The types that contributed to `computation` occurred within
Expand Down Expand Up @@ -84,15 +91,15 @@ impl FlagComputation {
&ty::GeneratorWitness(ref ts) => {
let mut computation = FlagComputation::new();
computation.add_tys(&ts.skip_binder()[..]);
self.add_bound_computation(&computation);
self.add_bound_computation(computation);
}

&ty::Closure(_, ref substs) => {
self.add_substs(substs);
}

&ty::Bound(debruijn, _) => {
self.add_binder(debruijn);
self.add_bound_var(debruijn);
}

&ty::Placeholder(..) => {
Expand Down Expand Up @@ -133,12 +140,12 @@ impl FlagComputation {
ty::ExistentialPredicate::Projection(p) => {
let mut proj_computation = FlagComputation::new();
proj_computation.add_existential_projection(&p);
self.add_bound_computation(&proj_computation);
self.add_bound_computation(proj_computation);
}
ty::ExistentialPredicate::AutoTrait(_) => {}
}
}
self.add_bound_computation(&computation);
self.add_bound_computation(computation);
self.add_region(r);
}

Expand Down Expand Up @@ -172,6 +179,63 @@ impl FlagComputation {
}
}

fn add_predicate_kind(&mut self, kind: &ty::PredicateKind<'_>) {
match kind {
ty::PredicateKind::Trait(trait_pred, _constness) => {
let mut computation = FlagComputation::new();
computation.add_substs(trait_pred.skip_binder().trait_ref.substs);

self.add_bound_computation(computation);
}
ty::PredicateKind::RegionOutlives(poly_outlives) => {
let mut computation = FlagComputation::new();
let ty::OutlivesPredicate(a, b) = poly_outlives.skip_binder();
computation.add_region(a);
computation.add_region(b);

self.add_bound_computation(computation);
}
ty::PredicateKind::TypeOutlives(poly_outlives) => {
let mut computation = FlagComputation::new();
let ty::OutlivesPredicate(ty, region) = poly_outlives.skip_binder();
computation.add_ty(ty);
computation.add_region(region);

self.add_bound_computation(computation);
}
ty::PredicateKind::Subtype(poly_subtype) => {
let mut computation = FlagComputation::new();
let ty::SubtypePredicate { a_is_expected: _, a, b } = poly_subtype.skip_binder();
computation.add_ty(a);
computation.add_ty(b);

self.add_bound_computation(computation);
}
ty::PredicateKind::Projection(projection) => {
let mut computation = FlagComputation::new();
let ty::ProjectionPredicate { projection_ty, ty } = projection.skip_binder();
computation.add_projection_ty(projection_ty);
computation.add_ty(ty);

self.add_bound_computation(computation);
}
ty::PredicateKind::WellFormed(arg) => {
self.add_substs(slice::from_ref(arg));
}
ty::PredicateKind::ObjectSafe(_def_id) => {}
ty::PredicateKind::ClosureKind(_def_id, substs, _kind) => {
self.add_substs(substs);
}
ty::PredicateKind::ConstEvaluatable(_def_id, substs) => {
self.add_substs(substs);
}
ty::PredicateKind::ConstEquate(expected, found) => {
self.add_const(expected);
self.add_const(found);
}
}
}

fn add_ty(&mut self, ty: Ty<'_>) {
self.add_flags(ty.flags);
self.add_exclusive_binder(ty.outer_exclusive_binder);
Expand All @@ -189,13 +253,13 @@ impl FlagComputation {
computation.add_tys(fn_sig.skip_binder().inputs());
computation.add_ty(fn_sig.skip_binder().output());

self.add_bound_computation(&computation);
self.add_bound_computation(computation);
}

fn add_region(&mut self, r: ty::Region<'_>) {
self.add_flags(r.type_flags());
if let ty::ReLateBound(debruijn, _) = *r {
self.add_binder(debruijn);
self.add_bound_var(debruijn);
}
}

Expand All @@ -214,7 +278,7 @@ impl FlagComputation {
}
}
ty::ConstKind::Bound(debruijn, _) => {
self.add_binder(debruijn);
self.add_bound_var(debruijn);
}
ty::ConstKind::Param(_) => {
self.add_flags(TypeFlags::HAS_CT_PARAM);
Expand Down
16 changes: 16 additions & 0 deletions src/librustc_middle/ty/fold.rs
Expand Up @@ -31,6 +31,7 @@
//! These methods return true to indicate that the visitor has found what it is
//! looking for, and does not need to visit anything else.

use crate::ty::structural_impls::PredicateVisitor;
use crate::ty::{self, flags::FlagComputation, Binder, Ty, TyCtxt, TypeFlags};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
Expand Down Expand Up @@ -908,6 +909,12 @@ impl<'tcx> TypeVisitor<'tcx> for HasEscapingVarsVisitor {
}
}

impl<'tcx> PredicateVisitor<'tcx> for HasEscapingVarsVisitor {
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
predicate.inner.outer_exclusive_binder > self.outer_index
}
}

// FIXME: Optimize for checking for infer flags
struct HasTypeFlagsVisitor {
flags: ty::TypeFlags,
Expand All @@ -932,6 +939,15 @@ impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor {
}
}

impl<'tcx> PredicateVisitor<'tcx> for HasTypeFlagsVisitor {
fn visit_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> bool {
debug!(
"HasTypeFlagsVisitor: predicate={:?} predicate.flags={:?} self.flags={:?}",
predicate, predicate.inner.flags, self.flags
);
predicate.inner.flags.intersects(self.flags)
}
}
/// Collects all the late-bound regions at the innermost binding level
/// into a hash set.
struct LateBoundRegionsCollector {
Expand Down
46 changes: 40 additions & 6 deletions src/librustc_middle/ty/mod.rs
Expand Up @@ -627,7 +627,7 @@ impl<'tcx> Hash for TyS<'tcx> {
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::TyS<'tcx> {
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for TyS<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let ty::TyS {
ref kind,
Expand Down Expand Up @@ -1001,16 +1001,35 @@ impl<'tcx> GenericPredicates<'tcx> {
}
}

#[derive(Clone, Copy, Hash, RustcEncodable, RustcDecodable, Lift)]
#[derive(HashStable)]
#[derive(Debug)]
crate struct PredicateInner<'tcx> {
kind: PredicateKind<'tcx>,
flags: TypeFlags,
/// See the comment for the corresponding field of [TyS].
outer_exclusive_binder: ty::DebruijnIndex,
}

#[cfg(target_arch = "x86_64")]
static_assert_size!(PredicateInner<'_>, 40);

#[derive(Clone, Copy, Lift)]
pub struct Predicate<'tcx> {
kind: &'tcx PredicateKind<'tcx>,
inner: &'tcx PredicateInner<'tcx>,
}

impl rustc_serialize::UseSpecializedEncodable for Predicate<'_> {}
impl rustc_serialize::UseSpecializedDecodable for Predicate<'_> {}

impl<'tcx> PartialEq for Predicate<'tcx> {
fn eq(&self, other: &Self) -> bool {
// `self.kind` is always interned.
ptr::eq(self.kind, other.kind)
ptr::eq(self.inner, other.inner)
}
}

impl Hash for Predicate<'_> {
fn hash<H: Hasher>(&self, s: &mut H) {
(self.inner as *const PredicateInner<'_>).hash(s)
}
}

Expand All @@ -1019,7 +1038,22 @@ impl<'tcx> Eq for Predicate<'tcx> {}
impl<'tcx> Predicate<'tcx> {
#[inline(always)]
pub fn kind(self) -> &'tcx PredicateKind<'tcx> {
self.kind
&self.inner.kind
}
}

impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
let PredicateInner {
ref kind,

// The other fields just provide fast access to information that is
// also contained in `kind`, so no need to hash them.
flags: _,
outer_exclusive_binder: _,
} = self.inner;

kind.hash_stable(hcx, hasher);
}
}

Expand Down

0 comments on commit f802ee1

Please sign in to comment.