Skip to content

Commit dcb3776

Browse files
committed
Always compute DepNode for incremental queries.
Currently we only compute it when necessary -- sometimes in `check_if_ensure_can_skip_execution`, sometimes in one of two places in `execute_job_incr` -- and pass around `Option<DepNode>` to allow this. This commit changes things so we always compute it up front for incremental queries. The performance cost is negligible and it simplifies things. - `check_if_ensure_can_skip_execution` can be made simpler, returning a bool and eliminating the need for `EnsureCanSkip`. - `execute_job_incr` no longer uses two slightly different methods to create a `DepNode` (`get_or_insert_with` vs `unwrap_or_else`).
1 parent c63cd67 commit dcb3776

File tree

1 file changed

+37
-62
lines changed

1 file changed

+37
-62
lines changed

compiler/rustc_query_impl/src/execution.rs

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ fn try_execute_query<'tcx, C: QueryCache, const INCR: bool>(
300300

301301
// Delegate to another function to actually execute the query job.
302302
let (value, dep_node_index) = if INCR {
303-
execute_job_incr(query, tcx, key, dep_node, id)
303+
execute_job_incr(query, tcx, key, dep_node.unwrap(), id)
304304
} else {
305305
execute_job_non_incr(query, tcx, key, id)
306306
};
@@ -416,27 +416,23 @@ fn execute_job_incr<'tcx, C: QueryCache>(
416416
query: &'tcx QueryVTable<'tcx, C>,
417417
tcx: TyCtxt<'tcx>,
418418
key: C::Key,
419-
mut dep_node_opt: Option<DepNode>,
419+
dep_node: DepNode,
420420
job_id: QueryJobId,
421421
) -> (C::Value, DepNodeIndex) {
422422
let dep_graph_data =
423423
tcx.dep_graph.data().expect("should always be present in incremental mode");
424424

425425
if !query.anon && !query.eval_always {
426-
// `to_dep_node` is expensive for some `DepKind`s.
427-
let dep_node =
428-
dep_node_opt.get_or_insert_with(|| DepNode::construct(tcx, query.dep_kind, &key));
429-
430426
// The diagnostics for this query will be promoted to the current session during
431427
// `try_mark_green()`, so we can ignore them here.
432428
if let Some(ret) = start_query(job_id, false, || try {
433-
let (prev_index, dep_node_index) = dep_graph_data.try_mark_green(tcx, dep_node)?;
429+
let (prev_index, dep_node_index) = dep_graph_data.try_mark_green(tcx, &dep_node)?;
434430
let value = load_from_disk_or_invoke_provider_green(
435431
tcx,
436432
dep_graph_data,
437433
query,
438434
key,
439-
dep_node,
435+
&dep_node,
440436
prev_index,
441437
dep_node_index,
442438
);
@@ -456,10 +452,6 @@ fn execute_job_incr<'tcx, C: QueryCache>(
456452
});
457453
}
458454

459-
// `to_dep_node` is expensive for some `DepKind`s.
460-
let dep_node =
461-
dep_node_opt.unwrap_or_else(|| DepNode::construct(tcx, query.dep_kind, &key));
462-
463455
// Call the query provider.
464456
dep_graph_data.with_task(
465457
dep_node,
@@ -571,69 +563,56 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
571563
value
572564
}
573565

574-
/// Return value struct for [`check_if_ensure_can_skip_execution`].
575-
struct EnsureCanSkip {
576-
/// If true, the current `tcx.ensure_ok()` or `tcx.ensure_done()` query
577-
/// can return early without actually trying to execute.
578-
skip_execution: bool,
579-
/// A dep node that was prepared while checking whether execution can be
580-
/// skipped, to be reused by execution itself if _not_ skipped.
581-
dep_node: Option<DepNode>,
582-
}
583-
584566
/// Checks whether a `tcx.ensure_ok()` or `tcx.ensure_done()` query call can
585567
/// return early without actually trying to execute.
586568
///
587569
/// This only makes sense during incremental compilation, because it relies
588570
/// on having the dependency graph (and in some cases a disk-cached value)
589571
/// from the previous incr-comp session.
590572
#[inline(never)]
591-
fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
573+
fn ensure_can_skip_execution<'tcx, C: QueryCache>(
592574
query: &'tcx QueryVTable<'tcx, C>,
593575
tcx: TyCtxt<'tcx>,
594576
key: C::Key,
577+
dep_node: DepNode,
595578
ensure_mode: EnsureMode,
596-
) -> EnsureCanSkip {
579+
) -> bool {
597580
// Queries with `eval_always` should never skip execution.
598581
if query.eval_always {
599-
return EnsureCanSkip { skip_execution: false, dep_node: None };
582+
return false;
600583
}
601584

602585
// Ensuring an anonymous query makes no sense
603586
assert!(!query.anon);
604587

605-
let dep_node = DepNode::construct(tcx, query.dep_kind, &key);
606-
607-
let serialized_dep_node_index = match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
588+
match tcx.dep_graph.try_mark_green(tcx, &dep_node) {
608589
None => {
609590
// A None return from `try_mark_green` means that this is either
610591
// a new dep node or that the dep node has already been marked red.
611592
// Either way, we can't call `dep_graph.read()` as we don't have the
612593
// DepNodeIndex. We must invoke the query itself. The performance cost
613594
// this introduces should be negligible as we'll immediately hit the
614595
// in-memory cache, or another query down the line will.
615-
return EnsureCanSkip { skip_execution: false, dep_node: Some(dep_node) };
596+
false
616597
}
617598
Some((serialized_dep_node_index, dep_node_index)) => {
618599
tcx.dep_graph.read_index(dep_node_index);
619600
tcx.prof.query_cache_hit(dep_node_index.into());
620-
serialized_dep_node_index
621-
}
622-
};
623-
624-
match ensure_mode {
625-
EnsureMode::Ok => {
626-
// In ensure-ok mode, we can skip execution for this key if the node
627-
// is green. It must have succeeded in the previous session, and
628-
// therefore would succeed in the current session if executed.
629-
EnsureCanSkip { skip_execution: true, dep_node: None }
630-
}
631-
EnsureMode::Done => {
632-
// In ensure-done mode, we can only skip execution for this key if
633-
// there's a disk-cached value available to load later if needed,
634-
// which guarantees the query provider will never run for this key.
635-
let is_loadable = (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index);
636-
EnsureCanSkip { skip_execution: is_loadable, dep_node: Some(dep_node) }
601+
match ensure_mode {
602+
// In ensure-ok mode, we can skip execution for this key if the
603+
// node is green. It must have succeeded in the previous
604+
// session, and therefore would succeed in the current session
605+
// if executed.
606+
EnsureMode::Ok => true,
607+
608+
// In ensure-done mode, we can only skip execution for this key
609+
// if there's a disk-cached value available to load later if
610+
// needed, which guarantees the query provider will never run
611+
// for this key.
612+
EnsureMode::Done => {
613+
(query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index)
614+
}
615+
}
637616
}
638617
}
639618
}
@@ -660,24 +639,20 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>(
660639
key: C::Key,
661640
mode: QueryMode,
662641
) -> Option<C::Value> {
642+
// There are scenarios where this `dep_node` is never used (e.g. for `anon` queries) but they
643+
// are rare enough that the wasted effort doesn't materially hurt performance.
644+
let dep_node = DepNode::construct(tcx, query.dep_kind, &key);
645+
663646
// Check if query execution can be skipped, for `ensure_ok` or `ensure_done`.
664-
// This might have the side-effect of creating a suitable DepNode, which
665-
// we should reuse for execution instead of creating a new one.
666-
let dep_node: Option<DepNode> = match mode {
667-
QueryMode::Ensure { ensure_mode } => {
668-
let EnsureCanSkip { skip_execution, dep_node } =
669-
check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode);
670-
if skip_execution {
671-
// Return early to skip execution.
672-
return None;
673-
}
674-
dep_node
675-
}
676-
QueryMode::Get => None,
677-
};
647+
if let QueryMode::Ensure { ensure_mode } = mode
648+
&& ensure_can_skip_execution(query, tcx, key, dep_node, ensure_mode)
649+
{
650+
return None;
651+
}
678652

679-
let (result, dep_node_index) =
680-
ensure_sufficient_stack(|| try_execute_query::<C, true>(query, tcx, span, key, dep_node));
653+
let (result, dep_node_index) = ensure_sufficient_stack(|| {
654+
try_execute_query::<C, true>(query, tcx, span, key, Some(dep_node))
655+
});
681656
if let Some(dep_node_index) = dep_node_index {
682657
tcx.dep_graph.read_index(dep_node_index)
683658
}

0 commit comments

Comments
 (0)