Shrink TyKind::FnPtr.

By splitting the `FnSig` within `TyKind::FnPtr` into `FnSigTys` and
`FnHeader`, which can be packed more efficiently. This reduces the size
of the hot `TyKind` type from 32 bytes to 24 bytes on 64-bit platforms.
This reduces peak memory usage by a few percent on some benchmarks. It
also reduces cache misses and page faults similarly, though this doesn't
translate to clear cycles or wall-time improvements on CI.
This commit is contained in:
Nicholas Nethercote 2024-08-08 17:18:20 +10:00
parent 8640998869
commit c4717cc9d1
89 changed files with 298 additions and 201 deletions

View file

@ -1087,9 +1087,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
values
}
(ty::FnDef(did1, args1), ty::FnPtr(sig2)) => {
(ty::FnDef(did1, args1), ty::FnPtr(sig_tys2, hdr2)) => {
let sig1 = self.tcx.fn_sig(*did1).instantiate(self.tcx, args1);
let mut values = self.cmp_fn_sig(&sig1, sig2);
let mut values = self.cmp_fn_sig(&sig1, &sig_tys2.with(*hdr2));
values.0.push_highlighted(format!(
" {{{}}}",
self.tcx.def_path_str_with_args(*did1, args1)
@ -1097,16 +1097,18 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
values
}
(ty::FnPtr(sig1), ty::FnDef(did2, args2)) => {
(ty::FnPtr(sig_tys1, hdr1), ty::FnDef(did2, args2)) => {
let sig2 = self.tcx.fn_sig(*did2).instantiate(self.tcx, args2);
let mut values = self.cmp_fn_sig(sig1, &sig2);
let mut values = self.cmp_fn_sig(&sig_tys1.with(*hdr1), &sig2);
values
.1
.push_normal(format!(" {{{}}}", self.tcx.def_path_str_with_args(*did2, args2)));
values
}
(ty::FnPtr(sig1), ty::FnPtr(sig2)) => self.cmp_fn_sig(sig1, sig2),
(ty::FnPtr(sig_tys1, hdr1), ty::FnPtr(sig_tys2, hdr2)) => {
self.cmp_fn_sig(&sig_tys1.with(*hdr1), &sig_tys2.with(*hdr2))
}
_ => {
let mut strs = (DiagStyledString::new(), DiagStyledString::new());

View file

@ -441,9 +441,9 @@ impl<T> Trait<T> for X {
}
}
}
(ty::FnPtr(sig), ty::FnDef(def_id, _))
| (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
if tcx.fn_sig(def_id).skip_binder().safety() < sig.safety() {
(ty::FnPtr(_, hdr), ty::FnDef(def_id, _))
| (ty::FnDef(def_id, _), ty::FnPtr(_, hdr)) => {
if tcx.fn_sig(def_id).skip_binder().safety() < hdr.safety {
diag.note(
"unsafe functions cannot be coerced into safe function pointers",
);

View file

@ -383,8 +383,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
return;
}
match (&expected_inner.kind(), &found_inner.kind()) {
(ty::FnPtr(sig), ty::FnDef(did, args)) => {
let expected_sig = &(self.normalize_fn_sig)(*sig);
(ty::FnPtr(sig_tys, hdr), ty::FnDef(did, args)) => {
let sig = sig_tys.with(*hdr);
let expected_sig = &(self.normalize_fn_sig)(sig);
let found_sig =
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did).instantiate(self.tcx, args));
@ -402,11 +403,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
(false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
(true, true) => {
diag.subdiagnostic(FnItemsAreDistinct);
FunctionPointerSuggestion::CastRef { span, fn_name, sig: *sig }
FunctionPointerSuggestion::CastRef { span, fn_name, sig }
}
(false, false) => {
diag.subdiagnostic(FnItemsAreDistinct);
FunctionPointerSuggestion::Cast { span, fn_name, sig: *sig }
FunctionPointerSuggestion::Cast { span, fn_name, sig }
}
};
diag.subdiagnostic(sugg);
@ -449,10 +450,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diag.subdiagnostic(sug);
}
(ty::FnDef(did, args), ty::FnPtr(sig)) => {
(ty::FnDef(did, args), ty::FnPtr(sig_tys, hdr)) => {
let expected_sig =
&(self.normalize_fn_sig)(self.tcx.fn_sig(*did).instantiate(self.tcx, args));
let found_sig = &(self.normalize_fn_sig)(*sig);
let found_sig = &(self.normalize_fn_sig)(sig_tys.with(*hdr));
if !self.same_type_modulo_infer(*found_sig, *expected_sig) {
return;

View file

@ -375,7 +375,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let impl_candidates = self.find_similar_impl_candidates(leaf_trait_predicate);
suggested = if let &[cand] = &impl_candidates[..] {
let cand = cand.trait_ref;
if let (ty::FnPtr(_), ty::FnDef(..)) =
if let (ty::FnPtr(..), ty::FnDef(..)) =
(cand.self_ty().kind(), main_trait_ref.self_ty().skip_binder().kind())
{
err.span_suggestion(
@ -793,8 +793,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
// if they have captures.
if let Some(by_ref_captures) = by_ref_captures
&& let ty::FnPtr(sig) = by_ref_captures.kind()
&& !sig.skip_binder().output().is_unit()
&& let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
&& !sig_tys.skip_binder().output().is_unit()
{
let mut err = self.dcx().create_err(AsyncClosureNotFn {
span: self.tcx.def_span(closure_def_id),
@ -1061,7 +1061,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
"`{ty}` is forbidden as the type of a const generic parameter",
)
}
ty::FnPtr(_) => {
ty::FnPtr(..) => {
struct_span_code_err!(
self.dcx(),
span,
@ -1844,10 +1844,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
if let &[cand] = &candidates[..] {
let (desc, mention_castable) =
match (cand.self_ty().kind(), trait_ref.self_ty().skip_binder().kind()) {
(ty::FnPtr(_), ty::FnDef(..)) => {
(ty::FnPtr(..), ty::FnDef(..)) => {
(" implemented for fn pointer `", ", cast using `as`")
}
(ty::FnPtr(_), _) => (" implemented for fn pointer `", ""),
(ty::FnPtr(..), _) => (" implemented for fn pointer `", ""),
_ => (" implemented for `", ""),
};
err.highlighted_help(vec![

View file

@ -1077,10 +1077,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let Some((def_id_or_name, output, inputs)) =
(self.autoderef_steps)(found).into_iter().find_map(|(found, _)| {
match *found.kind() {
ty::FnPtr(fn_sig) => Some((
ty::FnPtr(sig_tys, _) => Some((
DefIdOrName::Name("function pointer"),
fn_sig.output(),
fn_sig.inputs(),
sig_tys.output(),
sig_tys.inputs(),
)),
ty::FnDef(def_id, _) => {
let fn_sig = found.fn_sig(self.tcx);
@ -1977,20 +1977,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = cause else {
return;
};
let ty::FnPtr(expected) = expected.kind() else {
let ty::FnPtr(sig_tys, hdr) = expected.kind() else {
return;
};
let ty::FnPtr(found) = found.kind() else {
let expected = sig_tys.with(*hdr);
let ty::FnPtr(sig_tys, hdr) = found.kind() else {
return;
};
let found = sig_tys.with(*hdr);
let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id) else {
return;
};
let hir::ExprKind::Path(path) = arg.kind else {
return;
};
let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(*expected).inputs();
let found_inputs = self.tcx.instantiate_bound_regions_with_erased(*found).inputs();
let expected_inputs = self.tcx.instantiate_bound_regions_with_erased(expected).inputs();
let found_inputs = self.tcx.instantiate_bound_regions_with_erased(found).inputs();
let both_tys = expected_inputs.iter().copied().zip(found_inputs.iter().copied());
let arg_expr = |infcx: &InferCtxt<'tcx>, name, expected: Ty<'tcx>, found: Ty<'tcx>| {
@ -4790,13 +4792,13 @@ fn hint_missing_borrow<'tcx>(
}
let found_args = match found.kind() {
ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
kind => {
span_bug!(span, "found was converted to a FnPtr above but is now {:?}", kind)
}
};
let expected_args = match expected.kind() {
ty::FnPtr(f) => infcx.enter_forall(*f, |f| f.inputs().iter()),
ty::FnPtr(sig_tys, _) => infcx.enter_forall(*sig_tys, |sig_tys| sig_tys.inputs().iter()),
kind => {
span_bug!(span, "expected was converted to a FnPtr above but is now {:?}", kind)
}

View file

@ -1636,7 +1636,7 @@ fn confirm_fn_pointer_candidate<'cx, 'tcx>(
.generics_of(def_id)
.host_effect_index
.map_or(tcx.consts.true_, |idx| args.const_at(idx)),
ty::FnPtr(_) => tcx.consts.true_,
ty::FnPtr(..) => tcx.consts.true_,
_ => unreachable!("only expected FnPtr or FnDef in `confirm_fn_pointer_candidate`"),
};

View file

@ -33,7 +33,7 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Float(_)
| ty::Never
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Char
| ty::CoroutineWitness(..)
| ty::RawPtr(_, _)
@ -224,7 +224,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
| ty::RawPtr(..)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::CoroutineWitness(..) => {
// these types never have a destructor
}

View file

@ -468,8 +468,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates.vec.push(AsyncClosureCandidate);
}
// Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig) => {
if sig.is_fn_trait_compatible() {
ty::FnPtr(sig_tys, hdr) => {
if sig_tys.with(hdr).is_fn_trait_compatible() {
candidates.vec.push(AsyncClosureCandidate);
}
}
@ -535,8 +535,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
candidates.ambiguous = true; // Could wind up being a fn() type.
}
// Provide an impl, but only for suitable `fn` pointers.
ty::FnPtr(sig) => {
if sig.is_fn_trait_compatible() {
ty::FnPtr(sig_tys, hdr) => {
if sig_tys.with(hdr).is_fn_trait_compatible() {
candidates
.vec
.push(FnPointerCandidate { fn_host_effect: self.tcx().consts.true_ });
@ -819,7 +819,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
@ -1207,7 +1207,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Never
| ty::Foreign(_)
| ty::Array(..)
@ -1290,7 +1290,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::Ref(_, _, _)
| ty::FnDef(_, _)
| ty::Pat(_, _)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Dynamic(_, _, _)
| ty::Closure(..)
| ty::CoroutineClosure(..)
@ -1339,7 +1339,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let self_ty = self.infcx.resolve_vars_if_possible(obligation.self_ty());
match self_ty.skip_binder().kind() {
ty::FnPtr(_) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
ty::FnPtr(..) => candidates.vec.push(BuiltinCandidate { has_nested: false }),
ty::Bool
| ty::Char
| ty::Int(_)

View file

@ -1398,7 +1398,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
| ty::RawPtr(_, _)
| ty::Ref(..)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Never
| ty::Foreign(_) => {}

View file

@ -2114,7 +2114,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Bool
| ty::Float(_)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::RawPtr(..)
| ty::Char
| ty::Ref(..)
@ -2171,7 +2171,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
use self::BuiltinImplConditions::{Ambiguous, None, Where};
match *self_ty.kind() {
ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
ty::FnDef(..) | ty::FnPtr(..) | ty::Error(_) => Where(ty::Binder::dummy(Vec::new())),
ty::Uint(_)
| ty::Int(_)
@ -2333,7 +2333,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Bool
| ty::Float(_)
| ty::FnDef(..)
| ty::FnPtr(_)
| ty::FnPtr(..)
| ty::Error(_)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
| ty::Never

View file

@ -812,7 +812,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
return upvars.visit_with(self);
}
ty::FnPtr(_) => {
ty::FnPtr(..) => {
// Let the visitor iterate into the argument/return
// types appearing in the fn signature.
}