Skip to content

Commit ff40f2e

Browse files
committed
Auto merge of #101710 - jyn514:move-dep-kind-node, r=cjgillot
Move DepKindStruct from rustc_middle to rustc_query_system Helps with #96524. cc https://rust-lang.zulipchat.com/#narrow/stream/241847-t-compiler.2Fwg-incr-comp/topic/Moving.20.60DepKindStruct.60.20to.20rustc_query_system.20.2396524 r? `@cjgillot`
2 parents f5193a9 + 00cde6d commit ff40f2e

File tree

6 files changed

+135
-147
lines changed

6 files changed

+135
-147
lines changed

compiler/rustc_middle/src/dep_graph/dep_node.rs

+3-89
Original file line numberDiff line numberDiff line change
@@ -69,79 +69,6 @@ use std::hash::Hash;
6969

7070
pub use rustc_query_system::dep_graph::{DepContext, DepNodeParams};
7171

72-
/// This struct stores metadata about each DepKind.
73-
///
74-
/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
75-
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
76-
/// jump table instead of large matches.
77-
pub struct DepKindStruct<'tcx> {
78-
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
79-
/// When their result is needed, it is recomputed. They are useful for fine-grained
80-
/// dependency tracking, and caching within one compiler invocation.
81-
pub is_anon: bool,
82-
83-
/// Eval-always queries do not track their dependencies, and are always recomputed, even if
84-
/// their inputs have not changed since the last compiler invocation. The result is still
85-
/// cached within one compiler invocation.
86-
pub is_eval_always: bool,
87-
88-
/// Whether the query key can be recovered from the hashed fingerprint.
89-
/// See [DepNodeParams] trait for the behaviour of each key type.
90-
pub fingerprint_style: FingerprintStyle,
91-
92-
/// The red/green evaluation system will try to mark a specific DepNode in the
93-
/// dependency graph as green by recursively trying to mark the dependencies of
94-
/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
95-
/// where we don't know if it is red or green and we therefore actually have
96-
/// to recompute its value in order to find out. Since the only piece of
97-
/// information that we have at that point is the `DepNode` we are trying to
98-
/// re-evaluate, we need some way to re-run a query from just that. This is what
99-
/// `force_from_dep_node()` implements.
100-
///
101-
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
102-
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
103-
/// is usually constructed by computing a stable hash of the query-key that the
104-
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
105-
/// back from hash to query-key (since hash functions are not reversible). For
106-
/// this reason `force_from_dep_node()` is expected to fail from time to time
107-
/// because we just cannot find out, from the `DepNode` alone, what the
108-
/// corresponding query-key is and therefore cannot re-run the query.
109-
///
110-
/// The system deals with this case letting `try_mark_green` fail which forces
111-
/// the root query to be re-evaluated.
112-
///
113-
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
114-
/// Fortunately, we can use some contextual information that will allow us to
115-
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
116-
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
117-
/// valid `DefPathHash`. Since we also always build a huge table that maps every
118-
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
119-
/// everything we need to re-run the query.
120-
///
121-
/// Take the `mir_promoted` query as an example. Like many other queries, it
122-
/// just has a single parameter: the `DefId` of the item it will compute the
123-
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
124-
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
125-
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
126-
/// `DefId` in `tcx.def_path_hash_to_def_id`.
127-
pub force_from_dep_node: Option<fn(tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool>,
128-
129-
/// Invoke a query to put the on-disk cached value in memory.
130-
pub try_load_from_on_disk_cache: Option<fn(TyCtxt<'tcx>, DepNode)>,
131-
}
132-
133-
impl DepKind {
134-
#[inline(always)]
135-
pub fn fingerprint_style(self, tcx: TyCtxt<'_>) -> FingerprintStyle {
136-
// Only fetch the DepKindStruct once.
137-
let data = tcx.query_kind(self);
138-
if data.is_anon {
139-
return FingerprintStyle::Opaque;
140-
}
141-
data.fingerprint_style
142-
}
143-
}
144-
14572
macro_rules! define_dep_nodes {
14673
(
14774
$($(#[$attr:meta])*
@@ -159,7 +86,7 @@ macro_rules! define_dep_nodes {
15986
$( $( #[$attr] )* $variant),*
16087
}
16188

162-
fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
89+
pub(super) fn dep_kind_from_label_string(label: &str) -> Result<DepKind, ()> {
16390
match label {
16491
$(stringify!($variant) => Ok(DepKind::$variant),)*
16592
_ => Err(()),
@@ -214,11 +141,6 @@ static_assert_size!(DepNode, 18);
214141
static_assert_size!(DepNode, 24);
215142

216143
pub trait DepNodeExt: Sized {
217-
/// Construct a DepNode from the given DepKind and DefPathHash. This
218-
/// method will assert that the given DepKind actually requires a
219-
/// single DefId/DefPathHash parameter.
220-
fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> Self;
221-
222144
/// Extracts the DefId corresponding to this DepNode. This will work
223145
/// if two conditions are met:
224146
///
@@ -243,14 +165,6 @@ pub trait DepNodeExt: Sized {
243165
}
244166

245167
impl DepNodeExt for DepNode {
246-
/// Construct a DepNode from the given DepKind and DefPathHash. This
247-
/// method will assert that the given DepKind actually requires a
248-
/// single DefId/DefPathHash parameter.
249-
fn from_def_path_hash(tcx: TyCtxt<'_>, def_path_hash: DefPathHash, kind: DepKind) -> DepNode {
250-
debug_assert!(kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash);
251-
DepNode { kind, hash: def_path_hash.0.into() }
252-
}
253-
254168
/// Extracts the DefId corresponding to this DepNode. This will work
255169
/// if two conditions are met:
256170
///
@@ -262,7 +176,7 @@ impl DepNodeExt for DepNode {
262176
/// refers to something from the previous compilation session that
263177
/// has been removed.
264178
fn extract_def_id<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Option<DefId> {
265-
if self.kind.fingerprint_style(tcx) == FingerprintStyle::DefPathHash {
179+
if tcx.fingerprint_style(self.kind) == FingerprintStyle::DefPathHash {
266180
Some(tcx.def_path_hash_to_def_id(DefPathHash(self.hash.into()), &mut || {
267181
panic!("Failed to extract DefId: {:?} {}", self.kind, self.hash)
268182
}))
@@ -279,7 +193,7 @@ impl DepNodeExt for DepNode {
279193
) -> Result<DepNode, ()> {
280194
let kind = dep_kind_from_label_string(label)?;
281195

282-
match kind.fingerprint_style(tcx) {
196+
match tcx.fingerprint_style(kind) {
283197
FingerprintStyle::Opaque => Err(()),
284198
FingerprintStyle::Unit => Ok(DepNode::new_no_params(tcx, kind)),
285199
FingerprintStyle::DefPathHash => {

compiler/rustc_middle/src/dep_graph/mod.rs

+6-46
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@ pub use rustc_query_system::dep_graph::{
1111
SerializedDepNodeIndex, WorkProduct, WorkProductId,
1212
};
1313

14-
pub use dep_node::{label_strs, DepKind, DepKindStruct, DepNode, DepNodeExt};
14+
pub use dep_node::{label_strs, DepKind, DepNode, DepNodeExt};
1515
pub(crate) use dep_node::{make_compile_codegen_unit, make_compile_mono_item};
1616

1717
pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>;
18+
1819
pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>;
1920
pub type TaskDepsRef<'a> = rustc_query_system::dep_graph::TaskDepsRef<'a, DepKind>;
2021
pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>;
2122
pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>;
2223
pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>;
24+
pub type DepKindStruct<'tcx> = rustc_query_system::dep_graph::DepKindStruct<TyCtxt<'tcx>>;
2325

2426
impl rustc_query_system::dep_graph::DepKind for DepKind {
2527
const NULL: Self = DepKind::Null;
@@ -91,50 +93,8 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
9193
self.sess
9294
}
9395

94-
#[inline(always)]
95-
fn fingerprint_style(&self, kind: DepKind) -> rustc_query_system::dep_graph::FingerprintStyle {
96-
kind.fingerprint_style(*self)
97-
}
98-
99-
#[inline(always)]
100-
fn is_eval_always(&self, kind: DepKind) -> bool {
101-
self.query_kind(kind).is_eval_always
102-
}
103-
104-
fn try_force_from_dep_node(&self, dep_node: DepNode) -> bool {
105-
debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node);
106-
107-
// We must avoid ever having to call `force_from_dep_node()` for a
108-
// `DepNode::codegen_unit`:
109-
// Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
110-
// would always end up having to evaluate the first caller of the
111-
// `codegen_unit` query that *is* reconstructible. This might very well be
112-
// the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
113-
// to re-trigger calling the `codegen_unit` query with the right key. At
114-
// that point we would already have re-done all the work we are trying to
115-
// avoid doing in the first place.
116-
// The solution is simple: Just explicitly call the `codegen_unit` query for
117-
// each CGU, right after partitioning. This way `try_mark_green` will always
118-
// hit the cache instead of having to go through `force_from_dep_node`.
119-
// This assertion makes sure, we actually keep applying the solution above.
120-
debug_assert!(
121-
dep_node.kind != DepKind::codegen_unit,
122-
"calling force_from_dep_node() on DepKind::codegen_unit"
123-
);
124-
125-
let cb = self.query_kind(dep_node.kind);
126-
if let Some(f) = cb.force_from_dep_node {
127-
f(*self, dep_node);
128-
true
129-
} else {
130-
false
131-
}
132-
}
133-
134-
fn try_load_from_on_disk_cache(&self, dep_node: DepNode) {
135-
let cb = self.query_kind(dep_node.kind);
136-
if let Some(f) = cb.try_load_from_on_disk_cache {
137-
f(*self, dep_node)
138-
}
96+
#[inline]
97+
fn dep_kind_info(&self, dep_kind: DepKind) -> &DepKindStruct<'tcx> {
98+
&self.query_kinds[dep_kind as usize]
13999
}
140100
}

compiler/rustc_middle/src/ty/context.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! Type context book-keeping.
22
33
use crate::arena::Arena;
4-
use crate::dep_graph::{DepGraph, DepKind, DepKindStruct};
4+
use crate::dep_graph::{DepGraph, DepKindStruct};
55
use crate::hir::place::Place as HirPlace;
66
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
77
use crate::lint::{struct_lint_level, LintLevelSource};
@@ -1085,7 +1085,7 @@ pub struct GlobalCtxt<'tcx> {
10851085

10861086
pub queries: &'tcx dyn query::QueryEngine<'tcx>,
10871087
pub query_caches: query::QueryCaches<'tcx>,
1088-
query_kinds: &'tcx [DepKindStruct<'tcx>],
1088+
pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
10891089

10901090
// Internal caches for metadata decoding. No need to track deps on this.
10911091
pub ty_rcache: Lock<FxHashMap<ty::CReaderCacheKey, Ty<'tcx>>>,
@@ -1292,10 +1292,6 @@ impl<'tcx> TyCtxt<'tcx> {
12921292
}
12931293
}
12941294

1295-
pub(crate) fn query_kind(self, k: DepKind) -> &'tcx DepKindStruct<'tcx> {
1296-
&self.query_kinds[k as usize]
1297-
}
1298-
12991295
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` to ensure it gets used.
13001296
#[track_caller]
13011297
pub fn ty_error(self) -> Ty<'tcx> {

compiler/rustc_query_impl/src/plumbing.rs

+18
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,24 @@ where
380380
Q::Key: DepNodeParams<TyCtxt<'tcx>>,
381381
Q::Value: Value<TyCtxt<'tcx>>,
382382
{
383+
// We must avoid ever having to call `force_from_dep_node()` for a
384+
// `DepNode::codegen_unit`:
385+
// Since we cannot reconstruct the query key of a `DepNode::codegen_unit`, we
386+
// would always end up having to evaluate the first caller of the
387+
// `codegen_unit` query that *is* reconstructible. This might very well be
388+
// the `compile_codegen_unit` query, thus re-codegenning the whole CGU just
389+
// to re-trigger calling the `codegen_unit` query with the right key. At
390+
// that point we would already have re-done all the work we are trying to
391+
// avoid doing in the first place.
392+
// The solution is simple: Just explicitly call the `codegen_unit` query for
393+
// each CGU, right after partitioning. This way `try_mark_green` will always
394+
// hit the cache instead of having to go through `force_from_dep_node`.
395+
// This assertion makes sure, we actually keep applying the solution above.
396+
debug_assert!(
397+
dep_node.kind != DepKind::codegen_unit,
398+
"calling force_from_dep_node() on DepKind::codegen_unit"
399+
);
400+
383401
if let Some(key) = Q::Key::recover(tcx, &dep_node) {
384402
#[cfg(debug_assertions)]
385403
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();

compiler/rustc_query_system/src/dep_graph/dep_node.rs

+73
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ use crate::ich::StableHashingContext;
4747

4848
use rustc_data_structures::fingerprint::{Fingerprint, PackedFingerprint};
4949
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
50+
use rustc_hir::definitions::DefPathHash;
5051
use std::fmt;
5152
use std::hash::Hash;
5253

@@ -88,6 +89,17 @@ impl<K: DepKind> DepNode<K> {
8889

8990
dep_node
9091
}
92+
93+
/// Construct a DepNode from the given DepKind and DefPathHash. This
94+
/// method will assert that the given DepKind actually requires a
95+
/// single DefId/DefPathHash parameter.
96+
pub fn from_def_path_hash<Ctxt>(tcx: Ctxt, def_path_hash: DefPathHash, kind: K) -> Self
97+
where
98+
Ctxt: super::DepContext<DepKind = K>,
99+
{
100+
debug_assert!(tcx.fingerprint_style(kind) == FingerprintStyle::DefPathHash);
101+
DepNode { kind, hash: def_path_hash.0.into() }
102+
}
91103
}
92104

93105
impl<K: DepKind> fmt::Debug for DepNode<K> {
@@ -149,6 +161,67 @@ where
149161
}
150162
}
151163

164+
/// This struct stores metadata about each DepKind.
165+
///
166+
/// Information is retrieved by indexing the `DEP_KINDS` array using the integer value
167+
/// of the `DepKind`. Overall, this allows to implement `DepContext` using this manual
168+
/// jump table instead of large matches.
169+
pub struct DepKindStruct<CTX: DepContext> {
170+
/// Anonymous queries cannot be replayed from one compiler invocation to the next.
171+
/// When their result is needed, it is recomputed. They are useful for fine-grained
172+
/// dependency tracking, and caching within one compiler invocation.
173+
pub is_anon: bool,
174+
175+
/// Eval-always queries do not track their dependencies, and are always recomputed, even if
176+
/// their inputs have not changed since the last compiler invocation. The result is still
177+
/// cached within one compiler invocation.
178+
pub is_eval_always: bool,
179+
180+
/// Whether the query key can be recovered from the hashed fingerprint.
181+
/// See [DepNodeParams] trait for the behaviour of each key type.
182+
pub fingerprint_style: FingerprintStyle,
183+
184+
/// The red/green evaluation system will try to mark a specific DepNode in the
185+
/// dependency graph as green by recursively trying to mark the dependencies of
186+
/// that `DepNode` as green. While doing so, it will sometimes encounter a `DepNode`
187+
/// where we don't know if it is red or green and we therefore actually have
188+
/// to recompute its value in order to find out. Since the only piece of
189+
/// information that we have at that point is the `DepNode` we are trying to
190+
/// re-evaluate, we need some way to re-run a query from just that. This is what
191+
/// `force_from_dep_node()` implements.
192+
///
193+
/// In the general case, a `DepNode` consists of a `DepKind` and an opaque
194+
/// GUID/fingerprint that will uniquely identify the node. This GUID/fingerprint
195+
/// is usually constructed by computing a stable hash of the query-key that the
196+
/// `DepNode` corresponds to. Consequently, it is not in general possible to go
197+
/// back from hash to query-key (since hash functions are not reversible). For
198+
/// this reason `force_from_dep_node()` is expected to fail from time to time
199+
/// because we just cannot find out, from the `DepNode` alone, what the
200+
/// corresponding query-key is and therefore cannot re-run the query.
201+
///
202+
/// The system deals with this case letting `try_mark_green` fail which forces
203+
/// the root query to be re-evaluated.
204+
///
205+
/// Now, if `force_from_dep_node()` would always fail, it would be pretty useless.
206+
/// Fortunately, we can use some contextual information that will allow us to
207+
/// reconstruct query-keys for certain kinds of `DepNode`s. In particular, we
208+
/// enforce by construction that the GUID/fingerprint of certain `DepNode`s is a
209+
/// valid `DefPathHash`. Since we also always build a huge table that maps every
210+
/// `DefPathHash` in the current codebase to the corresponding `DefId`, we have
211+
/// everything we need to re-run the query.
212+
///
213+
/// Take the `mir_promoted` query as an example. Like many other queries, it
214+
/// just has a single parameter: the `DefId` of the item it will compute the
215+
/// validated MIR for. Now, when we call `force_from_dep_node()` on a `DepNode`
216+
/// with kind `MirValidated`, we know that the GUID/fingerprint of the `DepNode`
217+
/// is actually a `DefPathHash`, and can therefore just look up the corresponding
218+
/// `DefId` in `tcx.def_path_hash_to_def_id`.
219+
pub force_from_dep_node: Option<fn(tcx: CTX, dep_node: DepNode<CTX::DepKind>) -> bool>,
220+
221+
/// Invoke a query to put the on-disk cached value in memory.
222+
pub try_load_from_on_disk_cache: Option<fn(CTX, DepNode<CTX::DepKind>)>,
223+
}
224+
152225
/// A "work product" corresponds to a `.o` (or other) file that we
153226
/// save in between runs. These IDs do not have a `DefId` but rather
154227
/// some independent path or string that persists between runs without

0 commit comments

Comments
 (0)