Skip to content

Commit d54bfb0

Browse files
committed
global param_env canonicalization cache
1 parent c2ec908 commit d54bfb0

File tree

6 files changed

+128
-22
lines changed

6 files changed

+128
-22
lines changed

compiler/rustc_infer/src/infer/canonical/canonicalizer.rs

+79-15
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ impl<'tcx> InferCtxt<'tcx> {
3535
/// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query
3636
pub fn canonicalize_query<V>(
3737
&self,
38-
value: V,
38+
value: ty::ParamEnvAnd<'tcx, V>,
3939
query_state: &mut OriginalQueryValues<'tcx>,
40-
) -> Canonical<'tcx, V>
40+
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
4141
where
4242
V: TypeFoldable<TyCtxt<'tcx>>,
4343
{
44-
Canonicalizer::canonicalize(value, self, self.tcx, &CanonicalizeAllFreeRegions, query_state)
44+
self.canonicalize_query_with_mode(value, query_state, &CanonicalizeAllFreeRegions)
4545
}
4646

4747
/// Like [Self::canonicalize_query], but preserves distinct universes. For
@@ -126,19 +126,52 @@ impl<'tcx> InferCtxt<'tcx> {
126126
/// handling of `'static` regions (e.g. trait evaluation).
127127
pub fn canonicalize_query_keep_static<V>(
128128
&self,
129-
value: V,
129+
value: ty::ParamEnvAnd<'tcx, V>,
130130
query_state: &mut OriginalQueryValues<'tcx>,
131-
) -> Canonical<'tcx, V>
131+
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
132132
where
133133
V: TypeFoldable<TyCtxt<'tcx>>,
134134
{
135-
Canonicalizer::canonicalize(
135+
self.canonicalize_query_with_mode(
136+
value,
137+
query_state,
138+
&CanonicalizeFreeRegionsOtherThanStatic,
139+
)
140+
}
141+
142+
fn canonicalize_query_with_mode<V>(
143+
&self,
144+
value: ty::ParamEnvAnd<'tcx, V>,
145+
query_state: &mut OriginalQueryValues<'tcx>,
146+
canonicalize_region_mode: &dyn CanonicalizeMode,
147+
) -> Canonical<'tcx, ty::ParamEnvAnd<'tcx, V>>
148+
where
149+
V: TypeFoldable<TyCtxt<'tcx>>,
150+
{
151+
let (param_env, value) = value.into_parts();
152+
let base = self.tcx.canonical_param_env_cache.get_or_insert(
153+
param_env,
154+
query_state,
155+
|query_state| {
156+
Canonicalizer::canonicalize(
157+
param_env,
158+
self,
159+
self.tcx,
160+
&CanonicalizeFreeRegionsOtherThanStatic,
161+
query_state,
162+
)
163+
},
164+
);
165+
166+
Canonicalizer::canonicalize_with_base(
167+
base,
136168
value,
137169
self,
138170
self.tcx,
139-
&CanonicalizeFreeRegionsOtherThanStatic,
171+
canonicalize_region_mode,
140172
query_state,
141173
)
174+
.unchecked_map(|(param_env, value)| param_env.and(value))
142175
}
143176
}
144177

@@ -567,6 +600,33 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
567600
canonicalize_region_mode: &dyn CanonicalizeMode,
568601
query_state: &mut OriginalQueryValues<'tcx>,
569602
) -> Canonical<'tcx, V>
603+
where
604+
V: TypeFoldable<TyCtxt<'tcx>>,
605+
{
606+
let base = Canonical {
607+
max_universe: ty::UniverseIndex::ROOT,
608+
variables: List::empty(),
609+
value: (),
610+
};
611+
Canonicalizer::canonicalize_with_base(
612+
base,
613+
value,
614+
infcx,
615+
tcx,
616+
canonicalize_region_mode,
617+
query_state,
618+
)
619+
.unchecked_map(|((), val)| val)
620+
}
621+
622+
fn canonicalize_with_base<U, V>(
623+
base: Canonical<'tcx, U>,
624+
value: V,
625+
infcx: &InferCtxt<'tcx>,
626+
tcx: TyCtxt<'tcx>,
627+
canonicalize_region_mode: &dyn CanonicalizeMode,
628+
query_state: &mut OriginalQueryValues<'tcx>,
629+
) -> Canonical<'tcx, (U, V)>
570630
where
571631
V: TypeFoldable<TyCtxt<'tcx>>,
572632
{
@@ -578,24 +638,28 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
578638

579639
// Fast path: nothing that needs to be canonicalized.
580640
if !value.has_type_flags(needs_canonical_flags) {
581-
let canon_value = Canonical {
582-
max_universe: ty::UniverseIndex::ROOT,
583-
variables: List::empty(),
584-
value,
585-
};
586-
return canon_value;
641+
return base.unchecked_map(|b| (b, value));
587642
}
588643

589644
let mut canonicalizer = Canonicalizer {
590645
infcx,
591646
tcx,
592647
canonicalize_mode: canonicalize_region_mode,
593648
needs_canonical_flags,
594-
variables: SmallVec::new(),
649+
variables: SmallVec::from_slice(base.variables),
595650
query_state,
596651
indices: FxHashMap::default(),
597652
binder_index: ty::INNERMOST,
598653
};
654+
if canonicalizer.query_state.var_values.spilled() {
655+
canonicalizer.indices = canonicalizer
656+
.query_state
657+
.var_values
658+
.iter()
659+
.enumerate()
660+
.map(|(i, &kind)| (kind, BoundVar::new(i)))
661+
.collect();
662+
}
599663
let out_value = value.fold_with(&mut canonicalizer);
600664

601665
// Once we have canonicalized `out_value`, it should not
@@ -612,7 +676,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
612676
.max()
613677
.unwrap_or(ty::UniverseIndex::ROOT);
614678

615-
Canonical { max_universe, variables: canonical_variables, value: out_value }
679+
Canonical { max_universe, variables: canonical_variables, value: (base.value, out_value) }
616680
}
617681

618682
/// Creates a canonical variable replacing `kind` from the input,

compiler/rustc_infer/src/infer/combine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl<'tcx> InferCtxt<'tcx> {
171171
// two const param's types are able to be equal has to go through a canonical query with the actual logic
172172
// in `rustc_trait_selection`.
173173
let canonical = self.canonicalize_query(
174-
(relation.param_env(), a.ty(), b.ty()),
174+
relation.param_env().and((a.ty(), b.ty())),
175175
&mut OriginalQueryValues::default(),
176176
);
177177
self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {

compiler/rustc_middle/src/infer/canonical.rs

+37
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@
2121
//!
2222
//! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
2323
24+
use rustc_data_structures::fx::FxHashMap;
25+
use rustc_data_structures::sync::Lock;
2426
use rustc_macros::HashStable;
2527
use rustc_type_ir::Canonical as IrCanonical;
2628
use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo;
2729
pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
2830
use smallvec::SmallVec;
31+
use std::collections::hash_map::Entry;
2932
use std::ops::Index;
3033

3134
use crate::infer::MemberConstraint;
@@ -291,3 +294,37 @@ impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
291294
&self.var_values[value.as_usize()]
292295
}
293296
}
297+
298+
#[derive(Default)]
299+
pub struct CanonicalParamEnvCache<'tcx> {
300+
map: Lock<
301+
FxHashMap<
302+
ty::ParamEnv<'tcx>,
303+
(Canonical<'tcx, ty::ParamEnv<'tcx>>, OriginalQueryValues<'tcx>),
304+
>,
305+
>,
306+
}
307+
308+
impl<'tcx> CanonicalParamEnvCache<'tcx> {
309+
pub fn get_or_insert(
310+
&self,
311+
key: ty::ParamEnv<'tcx>,
312+
state: &mut OriginalQueryValues<'tcx>,
313+
canonicalize_op: impl FnOnce(
314+
&mut OriginalQueryValues<'tcx>,
315+
) -> Canonical<'tcx, ty::ParamEnv<'tcx>>,
316+
) -> Canonical<'tcx, ty::ParamEnv<'tcx>> {
317+
match self.map.borrow().entry(key) {
318+
Entry::Occupied(e) => {
319+
let (canonical, state_cached) = e.get();
320+
state.clone_from(state_cached);
321+
canonical.clone()
322+
}
323+
Entry::Vacant(e) => {
324+
let canonical = canonicalize_op(state);
325+
e.insert((canonical.clone(), state.clone()));
326+
canonical
327+
}
328+
}
329+
}
330+
}

compiler/rustc_middle/src/query/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2177,7 +2177,9 @@ rustc_queries! {
21772177
/// Used in `super_combine_consts` to ICE if the type of the two consts are definitely not going to end up being
21782178
/// equal to eachother. This might return `Ok` even if the types are not equal, but will never return `Err` if
21792179
/// the types might be equal.
2180-
query check_tys_might_be_eq(arg: Canonical<'tcx, (ty::ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>) -> Result<(), NoSolution> {
2180+
query check_tys_might_be_eq(
2181+
arg: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>
2182+
) -> Result<(), NoSolution> {
21812183
desc { "check whether two const param are definitely not equal to eachother"}
21822184
}
21832185

compiler/rustc_middle/src/ty/context.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub mod tls;
66

77
use crate::arena::Arena;
88
use crate::dep_graph::{DepGraph, DepKindStruct};
9-
use crate::infer::canonical::{CanonicalVarInfo, CanonicalVarInfos};
9+
use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
1010
use crate::lint::struct_lint_level;
1111
use crate::metadata::ModChild;
1212
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
@@ -612,6 +612,8 @@ pub struct GlobalCtxt<'tcx> {
612612
pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>,
613613
pub new_solver_coherence_evaluation_cache: solve::EvaluationCache<'tcx>,
614614

615+
pub canonical_param_env_cache: CanonicalParamEnvCache<'tcx>,
616+
615617
/// Data layout specification for the current target.
616618
pub data_layout: TargetDataLayout,
617619

@@ -774,6 +776,7 @@ impl<'tcx> TyCtxt<'tcx> {
774776
evaluation_cache: Default::default(),
775777
new_solver_evaluation_cache: Default::default(),
776778
new_solver_coherence_evaluation_cache: Default::default(),
779+
canonical_param_env_cache: Default::default(),
777780
data_layout,
778781
alloc_map: Lock::new(interpret::AllocMap::new()),
779782
}

compiler/rustc_trait_selection/src/traits/misc.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustc_infer::infer::canonical::Canonical;
99
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
1010
use rustc_infer::traits::query::NoSolution;
1111
use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
12-
use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
12+
use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt};
1313
use rustc_span::DUMMY_SP;
1414

1515
use super::outlives_bounds::InferCtxtExt;
@@ -209,10 +209,10 @@ pub fn all_fields_implement_trait<'tcx>(
209209

210210
pub fn check_tys_might_be_eq<'tcx>(
211211
tcx: TyCtxt<'tcx>,
212-
canonical: Canonical<'tcx, (ParamEnv<'tcx>, Ty<'tcx>, Ty<'tcx>)>,
212+
canonical: Canonical<'tcx, ty::ParamEnvAnd<'tcx, (Ty<'tcx>, Ty<'tcx>)>>,
213213
) -> Result<(), NoSolution> {
214-
let (infcx, (param_env, ty_a, ty_b), _) =
215-
tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
214+
let (infcx, key, _) = tcx.infer_ctxt().build_with_canonical(DUMMY_SP, &canonical);
215+
let (param_env, (ty_a, ty_b)) = key.into_parts();
216216
let ocx = ObligationCtxt::new(&infcx);
217217

218218
let result = ocx.eq(&ObligationCause::dummy(), param_env, ty_a, ty_b);

0 commit comments

Comments
 (0)