Skip to content

Commit 0be0df1

Browse files
committed
More aggressive inlining in the fast_reject code.
This code is very hot in a couple of benchmarks.
1 parent 00f2459 commit 0be0df1

File tree

3 files changed

+63
-20
lines changed

3 files changed

+63
-20
lines changed

compiler/rustc_trait_selection/src/traits/coherence.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,10 @@ pub fn overlapping_impls(
100100
let impl1_ref = tcx.impl_trait_ref(impl1_def_id);
101101
let impl2_ref = tcx.impl_trait_ref(impl2_def_id);
102102
let may_overlap = match (impl1_ref, impl2_ref) {
103-
(Some(a), Some(b)) => drcx.args_may_unify(a.skip_binder().args, b.skip_binder().args),
103+
(Some(a), Some(b)) => {
104+
// This call site can be hot.
105+
drcx.inlined_args_may_unify(a.skip_binder().args, b.skip_binder().args)
106+
}
104107
(None, None) => {
105108
let self_ty1 = tcx.type_of(impl1_def_id).skip_binder();
106109
let self_ty2 = tcx.type_of(impl2_def_id).skip_binder();

compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -561,9 +561,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
561561
// consider a "quick reject". This avoids creating more types
562562
// and so forth that we need to.
563563
let impl_trait_header = self.tcx().impl_trait_header(impl_def_id).unwrap();
564-
if !drcx
565-
.args_may_unify(obligation_args, impl_trait_header.trait_ref.skip_binder().args)
566-
{
564+
// This call site can be hot.
565+
if !drcx.inlined_args_may_unify(
566+
obligation_args,
567+
impl_trait_header.trait_ref.skip_binder().args,
568+
) {
567569
return;
568570
}
569571

compiler/rustc_type_ir/src/fast_reject.rs

+54-16
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,15 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
220220
// and small enough to prevent hangs.
221221
const STARTING_DEPTH: usize = 8;
222222

223+
#[inline(always)]
224+
pub fn inlined_args_may_unify(
225+
self,
226+
obligation_args: I::GenericArgs,
227+
impl_args: I::GenericArgs,
228+
) -> bool {
229+
self.inlined_args_may_unify_inner(obligation_args, impl_args, Self::STARTING_DEPTH)
230+
}
231+
223232
pub fn args_may_unify(
224233
self,
225234
obligation_args: I::GenericArgs,
@@ -228,32 +237,59 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
228237
self.args_may_unify_inner(obligation_args, impl_args, Self::STARTING_DEPTH)
229238
}
230239

231-
pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
232-
self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
240+
#[inline(always)]
241+
fn inlined_arg_may_unify(self, obl: I::GenericArg, imp: I::GenericArg, depth: usize) -> bool {
242+
match (obl.kind(), imp.kind()) {
243+
// We don't fast reject based on regions.
244+
(ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true,
245+
(ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => {
246+
self.types_may_unify_inner(obl, imp, depth)
247+
}
248+
(ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => {
249+
self.consts_may_unify_inner(obl, imp)
250+
}
251+
_ => panic!("kind mismatch: {obl:?} {imp:?}"),
252+
}
253+
}
254+
255+
fn arg_may_unify(self, obl: I::GenericArg, imp: I::GenericArg, depth: usize) -> bool {
256+
self.inlined_arg_may_unify(obl, imp, depth)
233257
}
234258

235259
fn args_may_unify_inner(
236260
self,
237261
obligation_args: I::GenericArgs,
238262
impl_args: I::GenericArgs,
239263
depth: usize,
264+
) -> bool {
265+
iter::zip(obligation_args.iter(), impl_args.iter())
266+
.all(|(obl, imp)| self.arg_may_unify(obl, imp, depth))
267+
}
268+
269+
#[inline(always)]
270+
fn inlined_args_may_unify_inner(
271+
self,
272+
obligation_args: I::GenericArgs,
273+
impl_args: I::GenericArgs,
274+
depth: usize,
240275
) -> bool {
241276
// No need to decrement the depth here as this function is only
242277
// recursively reachable via `types_may_unify_inner` which already
243278
// increments the depth for us.
244-
iter::zip(obligation_args.iter(), impl_args.iter()).all(|(obl, imp)| {
245-
match (obl.kind(), imp.kind()) {
246-
// We don't fast reject based on regions.
247-
(ty::GenericArgKind::Lifetime(_), ty::GenericArgKind::Lifetime(_)) => true,
248-
(ty::GenericArgKind::Type(obl), ty::GenericArgKind::Type(imp)) => {
249-
self.types_may_unify_inner(obl, imp, depth)
250-
}
251-
(ty::GenericArgKind::Const(obl), ty::GenericArgKind::Const(imp)) => {
252-
self.consts_may_unify_inner(obl, imp)
253-
}
254-
_ => panic!("kind mismatch: {obl:?} {imp:?}"),
255-
}
256-
})
279+
280+
// The len==1 case accounts for 99.9% of occurrences in the benchmarks
281+
// where this code is hot, e.g. `bitmaps-3.1.0` and `typenum-1.17.0`.
282+
if obligation_args.len() == 1 {
283+
let obl = obligation_args.as_slice()[0];
284+
let imp = impl_args.as_slice()[0];
285+
self.inlined_arg_may_unify(obl, imp, depth)
286+
} else {
287+
self.args_may_unify_inner(obligation_args, impl_args, depth)
288+
}
289+
}
290+
291+
pub fn types_may_unify(self, lhs: I::Ty, rhs: I::Ty) -> bool {
292+
self.types_may_unify_inner(lhs, rhs, Self::STARTING_DEPTH)
257293
}
258294

259295
fn types_may_unify_inner(self, lhs: I::Ty, rhs: I::Ty, depth: usize) -> bool {
@@ -320,7 +356,9 @@ impl<I: Interner, const INSTANTIATE_LHS_WITH_INFER: bool, const INSTANTIATE_RHS_
320356

321357
ty::Adt(lhs_def, lhs_args) => match rhs.kind() {
322358
ty::Adt(rhs_def, rhs_args) => {
323-
lhs_def == rhs_def && self.args_may_unify_inner(lhs_args, rhs_args, depth)
359+
// This call site can be hot.
360+
lhs_def == rhs_def
361+
&& self.inlined_args_may_unify_inner(lhs_args, rhs_args, depth)
324362
}
325363
_ => false,
326364
},

0 commit comments

Comments
 (0)