Pack Term in the same way as GenericArg.

This shrinks the `PredicateS` type, which is instanted frequently.
This commit is contained in:
Nicholas Nethercote
2022-09-05 14:03:53 +10:00
parent d565d51071
commit 79db32b64e
20 changed files with 191 additions and 108 deletions

View File

@@ -40,6 +40,7 @@ use rustc_hir::Node;
use rustc_index::vec::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{ExpnId, Span};
@@ -49,6 +50,9 @@ pub use vtable::*;
use std::fmt::Debug;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
use std::num::NonZeroUsize;
use std::ops::ControlFlow;
use std::{fmt, str};
@@ -902,42 +906,122 @@ pub struct CoercePredicate<'tcx> {
}
pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub enum Term<'tcx> {
Ty(Ty<'tcx>),
Const(Const<'tcx>),
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Term<'tcx> {
ptr: NonZeroUsize,
marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
}
impl<'tcx> From<Ty<'tcx>> for Term<'tcx> {
fn from(ty: Ty<'tcx>) -> Self {
Term::Ty(ty)
TermKind::Ty(ty).pack()
}
}
impl<'tcx> From<Const<'tcx>> for Term<'tcx> {
fn from(c: Const<'tcx>) -> Self {
Term::Const(c)
TermKind::Const(c).pack()
}
}
impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Term<'tcx> {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
self.unpack().hash_stable(hcx, hasher);
}
}
impl<'tcx> TypeFoldable<'tcx> for Term<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<'tcx>>(self, folder: &mut F) -> Result<Self, F::Error> {
Ok(self.unpack().try_fold_with(folder)?.pack())
}
}
impl<'tcx> TypeVisitable<'tcx> for Term<'tcx> {
fn visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.unpack().visit_with(visitor)
}
}
impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for Term<'tcx> {
fn encode(&self, e: &mut E) {
self.unpack().encode(e)
}
}
impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for Term<'tcx> {
fn decode(d: &mut D) -> Self {
let res: TermKind<'tcx> = Decodable::decode(d);
res.pack()
}
}
impl<'tcx> Term<'tcx> {
#[inline]
pub fn unpack(self) -> TermKind<'tcx> {
let ptr = self.ptr.get();
// SAFETY: use of `Interned::new_unchecked` here is ok because these
// pointers were originally created from `Interned` types in `pack()`,
// and this is just going in the other direction.
unsafe {
match ptr & TAG_MASK {
TYPE_TAG => TermKind::Ty(Ty(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const WithStableHash<ty::TyS<'tcx>>),
))),
CONST_TAG => TermKind::Const(ty::Const(Interned::new_unchecked(
&*((ptr & !TAG_MASK) as *const ty::ConstS<'tcx>),
))),
_ => core::intrinsics::unreachable(),
}
}
}
pub fn ty(&self) -> Option<Ty<'tcx>> {
if let Term::Ty(ty) = self { Some(*ty) } else { None }
if let TermKind::Ty(ty) = self.unpack() { Some(ty) } else { None }
}
pub fn ct(&self) -> Option<Const<'tcx>> {
if let Term::Const(c) = self { Some(*c) } else { None }
if let TermKind::Const(c) = self.unpack() { Some(c) } else { None }
}
pub fn into_arg(self) -> GenericArg<'tcx> {
match self {
Term::Ty(ty) => ty.into(),
Term::Const(c) => c.into(),
match self.unpack() {
TermKind::Ty(ty) => ty.into(),
TermKind::Const(c) => c.into(),
}
}
}
const TAG_MASK: usize = 0b11;
const TYPE_TAG: usize = 0b00;
const CONST_TAG: usize = 0b01;
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub enum TermKind<'tcx> {
Ty(Ty<'tcx>),
Const(Const<'tcx>),
}
impl<'tcx> TermKind<'tcx> {
#[inline]
fn pack(self) -> Term<'tcx> {
let (tag, ptr) = match self {
TermKind::Ty(ty) => {
// Ensure we can use the tag bits.
assert_eq!(mem::align_of_val(&*ty.0.0) & TAG_MASK, 0);
(TYPE_TAG, ty.0.0 as *const WithStableHash<ty::TyS<'tcx>> as usize)
}
TermKind::Const(ct) => {
// Ensure we can use the tag bits.
assert_eq!(mem::align_of_val(&*ct.0.0) & TAG_MASK, 0);
(CONST_TAG, ct.0.0 as *const ty::ConstS<'tcx> as usize)
}
};
Term { ptr: unsafe { NonZeroUsize::new_unchecked(ptr | tag) }, marker: PhantomData }
}
}
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@@ -2528,7 +2612,7 @@ mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
// These are in alphabetical order, which is easy to maintain.
static_assert_size!(PredicateS<'_>, 56);
static_assert_size!(PredicateS<'_>, 48);
static_assert_size!(TyS<'_>, 40);
static_assert_size!(WithStableHash<TyS<'_>>, 56);
}