Skip to content

Commit 237f82c

Browse files
committed
Auto merge of #154279 - nnethercote:refactor-execute_job_incr, r=<try>
Refactor `execute_job_incr`
2 parents 212b0d4 + f7fed56 commit 237f82c

7 files changed

Lines changed: 96 additions & 160 deletions

File tree

compiler/rustc_middle/src/dep_graph/graph.rs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex
2727
use super::{DepKind, DepNode, WorkProductId, read_deps, with_deps};
2828
use crate::dep_graph::edges::EdgesVec;
2929
use crate::ich::StableHashingContext;
30+
use crate::query::{QueryCache, QueryVTable};
3031
use crate::ty::TyCtxt;
3132
use crate::verify_ich::incremental_verify_ich;
3233

@@ -572,13 +573,12 @@ impl DepGraph {
572573
/// FIXME: If the code is changed enough for this node to be marked before requiring the
573574
/// caller's node, we suppose that those changes will be enough to mark this node red and
574575
/// force a recomputation using the "normal" way.
575-
pub fn with_feed_task<'tcx, R>(
576+
pub fn with_feed_task<'tcx, C: QueryCache>(
576577
&self,
577-
node: DepNode,
578578
tcx: TyCtxt<'tcx>,
579-
result: &R,
580-
hash_result: Option<fn(&mut StableHashingContext<'_>, &R) -> Fingerprint>,
581-
format_value_fn: fn(&R) -> String,
579+
query: &'tcx QueryVTable<'tcx, C>,
580+
node: DepNode,
581+
value: &C::Value,
582582
) -> DepNodeIndex {
583583
if let Some(data) = self.data.as_ref() {
584584
// The caller query has more dependencies than the node we are creating. We may
@@ -590,17 +590,10 @@ impl DepGraph {
590590
if let Some(prev_index) = data.previous.node_to_index_opt(&node) {
591591
let dep_node_index = data.colors.current(prev_index);
592592
if let Some(dep_node_index) = dep_node_index {
593-
incremental_verify_ich(
594-
tcx,
595-
data,
596-
result,
597-
prev_index,
598-
hash_result,
599-
format_value_fn,
600-
);
593+
incremental_verify_ich(tcx, data, query, value, prev_index);
601594

602595
#[cfg(debug_assertions)]
603-
if hash_result.is_some() {
596+
if query.hash_value_fn.is_some() {
604597
data.current.record_edge(
605598
dep_node_index,
606599
node,
@@ -624,7 +617,7 @@ impl DepGraph {
624617
}
625618
});
626619

627-
data.hash_result_and_alloc_node(tcx, node, edges, result, hash_result)
620+
data.hash_result_and_alloc_node(tcx, node, edges, value, query.hash_value_fn)
628621
} else {
629622
// Incremental compilation is turned off. We just execute the task
630623
// without tracking. We still provide a dep-node index that uniquely

compiler/rustc_middle/src/query/inner.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,7 @@ pub(crate) fn query_feed<'tcx, C>(
158158
// There is no cached value for this key, so feed the query by
159159
// adding the provided value to the cache.
160160
let dep_node = dep_graph::DepNode::construct(tcx, query.dep_kind, &key);
161-
let dep_node_index = tcx.dep_graph.with_feed_task(
162-
dep_node,
163-
tcx,
164-
&value,
165-
query.hash_value_fn,
166-
query.format_value,
167-
);
161+
let dep_node_index = tcx.dep_graph.with_feed_task(tcx, query, dep_node, &value);
168162
query.cache.complete(key, value, dep_node_index);
169163
}
170164
}

compiler/rustc_middle/src/query/plumbing.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use rustc_data_structures::sync::{AtomicU64, WorkerLocal};
88
use rustc_errors::Diag;
99
use rustc_span::Span;
1010

11-
use crate::dep_graph::{DepKind, DepNodeIndex, SerializedDepNodeIndex};
11+
use crate::dep_graph::{DepKind, SerializedDepNodeIndex};
1212
use crate::ich::StableHashingContext;
1313
use crate::queries::{ExternProviders, Providers, QueryArenas, QueryVTables, TaggedQueryKey};
1414
use crate::query::on_disk_cache::OnDiskCache;
@@ -97,12 +97,11 @@ pub struct QueryVTable<'tcx, C: QueryCache> {
9797

9898
pub will_cache_on_disk_for_key_fn: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> bool,
9999

100-
pub try_load_from_disk_fn: fn(
101-
tcx: TyCtxt<'tcx>,
102-
key: C::Key,
103-
prev_index: SerializedDepNodeIndex,
104-
index: DepNodeIndex,
105-
) -> Option<C::Value>,
100+
/// Function pointer that tries to load a query value from disk.
101+
///
102+
/// This should only be called after a successful check of `will_cache_on_disk_for_key_fn`.
103+
pub try_load_from_disk_fn:
104+
fn(tcx: TyCtxt<'tcx>, prev_index: SerializedDepNodeIndex) -> Option<C::Value>,
106105

107106
/// Function pointer that hashes this query's result values.
108107
///

compiler/rustc_middle/src/verify_ich.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,30 @@ use rustc_data_structures::fingerprint::Fingerprint;
44
use tracing::instrument;
55

66
use crate::dep_graph::{DepGraphData, SerializedDepNodeIndex};
7-
use crate::ich::StableHashingContext;
7+
use crate::query::{QueryCache, QueryVTable};
88
use crate::ty::TyCtxt;
99

1010
#[inline]
11-
#[instrument(skip(tcx, dep_graph_data, result, hash_result, format_value), level = "debug")]
12-
pub fn incremental_verify_ich<'tcx, V>(
11+
#[instrument(skip(tcx, query, dep_graph_data, result), level = "debug")]
12+
pub fn incremental_verify_ich<'tcx, C: QueryCache>(
1313
tcx: TyCtxt<'tcx>,
1414
dep_graph_data: &DepGraphData,
15-
result: &V,
15+
query: &'tcx QueryVTable<'tcx, C>,
16+
result: &C::Value,
1617
prev_index: SerializedDepNodeIndex,
17-
hash_result: Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>,
18-
format_value: fn(&V) -> String,
1918
) {
2019
if !dep_graph_data.is_index_green(prev_index) {
2120
incremental_verify_ich_not_green(tcx, prev_index)
2221
}
2322

24-
let new_hash = hash_result.map_or(Fingerprint::ZERO, |f| {
23+
let new_hash = query.hash_value_fn.map_or(Fingerprint::ZERO, |f| {
2524
tcx.with_stable_hashing_context(|mut hcx| f(&mut hcx, result))
2625
});
2726

2827
let old_hash = dep_graph_data.prev_value_fingerprint_of(prev_index);
2928

3029
if new_hash != old_hash {
31-
incremental_verify_ich_failed(tcx, prev_index, &|| format_value(result));
30+
incremental_verify_ich_failed(tcx, prev_index, &|| (query.format_value)(result));
3231
}
3332
}
3433

compiler/rustc_query_impl/src/execution.rs

Lines changed: 68 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
66
use rustc_data_structures::sync::{DynSend, DynSync};
77
use rustc_data_structures::{outline, sharded, sync};
88
use rustc_errors::FatalError;
9-
use rustc_middle::dep_graph::{DepGraphData, DepNodeKey, SerializedDepNodeIndex};
9+
use rustc_middle::dep_graph::DepNodeKey;
1010
use rustc_middle::query::{
1111
ActiveKeyStatus, CycleError, EnsureMode, QueryCache, QueryJob, QueryJobId, QueryKey,
1212
QueryLatch, QueryMode, QueryState, QueryVTable,
@@ -380,7 +380,6 @@ fn check_feedable_consistency<'tcx, C: QueryCache>(
380380
}
381381
}
382382

383-
// Fast path for when incr. comp. is off.
384383
#[inline(always)]
385384
fn execute_job_non_incr<'tcx, C: QueryCache>(
386385
query: &'tcx QueryVTable<'tcx, C>,
@@ -391,12 +390,13 @@ fn execute_job_non_incr<'tcx, C: QueryCache>(
391390
debug_assert!(!tcx.dep_graph.is_fully_enabled());
392391

393392
let prof_timer = tcx.prof.query_provider();
394-
// Call the query provider.
395393
let value = start_query(job_id, query.depth_limit, || (query.invoke_provider_fn)(tcx, key));
396394
let dep_node_index = tcx.dep_graph.next_virtual_depnode_index();
397395
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
398396

399397
// Sanity: Fingerprint the key and the result to assert they don't contain anything unhashable.
398+
// (There is no corresponding sanity check in `execute_job_incr` because it fingerprints the
399+
// key and result as part of its normal operation.)
400400
if cfg!(debug_assertions) {
401401
let _ = key.to_fingerprint(tcx);
402402
if let Some(hash_value_fn) = query.hash_value_fn {
@@ -420,116 +420,80 @@ fn execute_job_incr<'tcx, C: QueryCache>(
420420
let dep_graph_data =
421421
tcx.dep_graph.data().expect("should always be present in incremental mode");
422422

423-
if !query.eval_always {
424-
// The diagnostics for this query will be promoted to the current session during
425-
// `try_mark_green()`, so we can ignore them here.
426-
if let Some(ret) = start_query(job_id, false, || try {
427-
let (prev_index, dep_node_index) = dep_graph_data.try_mark_green(tcx, &dep_node)?;
428-
let value = load_from_disk_or_invoke_provider_green(
429-
tcx,
430-
dep_graph_data,
431-
query,
432-
key,
433-
&dep_node,
434-
prev_index,
435-
dep_node_index,
436-
);
437-
(value, dep_node_index)
438-
}) {
439-
return ret;
440-
}
441-
}
442-
443-
let prof_timer = tcx.prof.query_provider();
444-
445-
let (result, dep_node_index) = start_query(job_id, query.depth_limit, || {
446-
// Call the query provider.
447-
dep_graph_data.with_task(
448-
dep_node,
449-
tcx,
450-
(query, key),
451-
|tcx, (query, key)| (query.invoke_provider_fn)(tcx, key),
452-
query.hash_value_fn,
453-
)
454-
});
423+
if !query.eval_always
424+
&& let Some((prev_index, dep_node_index)) = dep_graph_data.try_mark_green(tcx, &dep_node)
425+
{
426+
// Note this function can be called concurrently from the same query. We must ensure that
427+
// this is handled correctly.
428+
429+
// First try to load the result from the on-disk cache. Some things are never cached on
430+
// disk.
431+
let try_value = if (query.will_cache_on_disk_for_key_fn)(tcx, key) {
432+
let prof_timer = tcx.prof.incr_cache_loading();
433+
let value = (query.try_load_from_disk_fn)(tcx, prev_index);
434+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
435+
value
436+
} else {
437+
None
438+
};
455439

456-
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
440+
let (value, verify) = match try_value {
441+
Some(value) => {
442+
if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) {
443+
dep_graph_data.mark_debug_loaded_from_disk(dep_node)
444+
}
457445

458-
(result, dep_node_index)
459-
}
446+
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
447+
// If `-Zincremental-verify-ich` is specified, re-hash every result from the cache
448+
// to make sure is has the expected fingerprint. Otherwise, re-hash a fraction to
449+
// give some coverage at low cost.
450+
let verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
451+
|| tcx.sess.opts.unstable_opts.incremental_verify_ich;
460452

461-
/// Given that the dep node for this query+key is green, obtain a value for it
462-
/// by loading one from disk if possible, or by invoking its query provider if
463-
/// necessary.
464-
#[inline(always)]
465-
fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
466-
tcx: TyCtxt<'tcx>,
467-
dep_graph_data: &DepGraphData,
468-
query: &'tcx QueryVTable<'tcx, C>,
469-
key: C::Key,
470-
dep_node: &DepNode,
471-
prev_index: SerializedDepNodeIndex,
472-
dep_node_index: DepNodeIndex,
473-
) -> C::Value {
474-
// Note this function can be called concurrently from the same query
475-
// We must ensure that this is handled correctly.
476-
477-
debug_assert!(dep_graph_data.is_index_green(prev_index));
478-
479-
// First try to load the result from the on-disk cache. Some things are never cached on disk.
480-
let value;
481-
let verify;
482-
match (query.try_load_from_disk_fn)(tcx, key, prev_index, dep_node_index) {
483-
Some(loaded_value) => {
484-
if std::intrinsics::unlikely(tcx.sess.opts.unstable_opts.query_dep_graph) {
485-
dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
453+
(value, verify)
486454
}
455+
None => {
456+
// We could not load a result from the on-disk cache, so recompute. The dep-graph
457+
// for this computation is already in-place, so we can just call the query
458+
// provider.
459+
let prof_timer = tcx.prof.query_provider();
460+
let value = start_query(job_id, query.depth_limit, || {
461+
tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key))
462+
});
463+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
464+
465+
(value, true)
466+
}
467+
};
487468

488-
value = loaded_value;
489-
490-
let prev_fingerprint = dep_graph_data.prev_value_fingerprint_of(prev_index);
491-
// If `-Zincremental-verify-ich` is specified, re-hash results from
492-
// the cache and make sure that they have the expected fingerprint.
469+
if verify {
470+
// Verify that re-running the query produced a result with the expected hash. This
471+
// catches bugs in query implementations, turning them into ICEs. For example, a query
472+
// might sort its result by `DefId`. Because `DefId`s are not stable across compilation
473+
// sessions, the result could get up getting sorted in a different order when the query
474+
// is re-run, even though all of the inputs (e.g. `DefPathHash` values) were green.
493475
//
494-
// If not, we still seek to verify a subset of fingerprints loaded
495-
// from disk. Re-hashing results is fairly expensive, so we can't
496-
// currently afford to verify every hash. This subset should still
497-
// give us some coverage of potential bugs.
498-
verify = prev_fingerprint.split().1.as_u64().is_multiple_of(32)
499-
|| tcx.sess.opts.unstable_opts.incremental_verify_ich;
500-
}
501-
None => {
502-
// We could not load a result from the on-disk cache, so recompute. The dep-graph for
503-
// this computation is already in-place, so we can just call the query provider.
504-
let prof_timer = tcx.prof.query_provider();
505-
value = tcx.dep_graph.with_ignore(|| (query.invoke_provider_fn)(tcx, key));
506-
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
507-
508-
verify = true;
476+
// See issue #82920 for an example of a miscompilation that would get turned into an
477+
// ICE by this check.
478+
incremental_verify_ich(tcx, dep_graph_data, query, &value, prev_index);
509479
}
510-
};
511480

512-
if verify {
513-
// Verify that re-running the query produced a result with the expected hash.
514-
// This catches bugs in query implementations, turning them into ICEs.
515-
// For example, a query might sort its result by `DefId` - since `DefId`s are
516-
// not stable across compilation sessions, the result could get up getting sorted
517-
// in a different order when the query is re-run, even though all of the inputs
518-
// (e.g. `DefPathHash` values) were green.
519-
//
520-
// See issue #82920 for an example of a miscompilation that would get turned into
521-
// an ICE by this check
522-
incremental_verify_ich(
523-
tcx,
524-
dep_graph_data,
525-
&value,
526-
prev_index,
527-
query.hash_value_fn,
528-
query.format_value,
529-
);
481+
(value, dep_node_index)
482+
} else {
483+
let prof_timer = tcx.prof.query_provider();
484+
let (value, dep_node_index) = start_query(job_id, query.depth_limit, || {
485+
dep_graph_data.with_task(
486+
dep_node,
487+
tcx,
488+
(query, key),
489+
|tcx, (query, key)| (query.invoke_provider_fn)(tcx, key),
490+
query.hash_value_fn,
491+
)
492+
});
493+
prof_timer.finish_with_query_invocation_id(dep_node_index.into());
494+
495+
(value, dep_node_index)
530496
}
531-
532-
value
533497
}
534498

535499
/// Checks whether a `tcx.ensure_ok()` or `tcx.ensure_done()` query call can

compiler/rustc_query_impl/src/plumbing.rs

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use rustc_index::Idx;
66
use rustc_middle::bug;
77
#[expect(unused_imports, reason = "used by doc comments")]
88
use rustc_middle::dep_graph::DepKindVTable;
9-
use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, DepNodeKey, SerializedDepNodeIndex};
9+
use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeKey, SerializedDepNodeIndex};
1010
use rustc_middle::query::erase::{Erasable, Erased};
1111
use rustc_middle::query::on_disk_cache::{
1212
AbsoluteBytePos, CacheDecoder, CacheEncoder, EncodedDepNodeIndex,
@@ -200,25 +200,17 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeI
200200
pub(crate) fn try_load_from_disk<'tcx, V>(
201201
tcx: TyCtxt<'tcx>,
202202
prev_index: SerializedDepNodeIndex,
203-
index: DepNodeIndex,
204203
) -> Option<V>
205204
where
206205
V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
207206
{
208207
let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
209208

210-
let prof_timer = tcx.prof.incr_cache_loading();
211-
212209
// The call to `with_query_deserialization` enforces that no new `DepNodes`
213210
// are created during deserialization. See the docs of that method for more
214211
// details.
215-
let value = tcx
216-
.dep_graph
217-
.with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index));
218-
219-
prof_timer.finish_with_query_invocation_id(index.into());
220-
221-
value
212+
tcx.dep_graph
213+
.with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index))
222214
}
223215

224216
/// Implementation of [`DepKindVTable::force_from_dep_node_fn`] for queries.

0 commit comments

Comments
 (0)