Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 20 additions & 15 deletions compiler/rustc_middle/src/query/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,21 +79,26 @@ where
{
match try_get_cached(tcx, &query.cache, key) {
Some(value) => erase::restore_val(value).map(drop),
None => (query.execute_query_fn)(
tcx,
DUMMY_SP,
key,
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
)
.map(erase::restore_val)
.map(|value| value.map(drop))
// Either we actually executed the query, which means we got a full `Result`,
// or we can just assume the query succeeded, because it was green in the
// incremental cache. If it is green, that means that the previous compilation
// that wrote to the incremental cache compiles successfully. That is only
// possible if the cache entry was `Ok(())`, so we emit that here, without
// actually encoding the `Result` in the cache or loading it from there.
.unwrap_or(Ok(())),
None => {
match (query.execute_query_fn)(
tcx,
DUMMY_SP,
key,
QueryMode::Ensure { ensure_mode: EnsureMode::Ok },
) {
// We executed the query. If the restored result is `Ok(_)`, dropping it converts
// it to `Ok(())`. If the restored result is `Err(guar)`, we pass that along.
Some(res) => erase::restore_val(res).map(drop),

// Reaching here means we didn't execute the query, but we can just assume the
// query succeeded, because it was green in the incremental cache. If it is green,
// that means that the previous compilation that wrote to the incremental cache
// compiles successfully. That is only possible if the cache entry was `Ok(())`, so
// we emit that here, without actually encoding the `Result` in the cache or
// loading it from there.
None => Ok(()),
}
}
}
}

Expand Down
38 changes: 18 additions & 20 deletions compiler/rustc_query_impl/src/execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,14 +572,12 @@ fn load_from_disk_or_invoke_provider_green<'tcx, C: QueryCache>(
value
}

/// Return value struct for [`check_if_ensure_can_skip_execution`].
struct EnsureCanSkip {
/// If true, the current `tcx.ensure_ok()` or `tcx.ensure_done()` query
/// can return early without actually trying to execute.
skip_execution: bool,
/// A dep node that was prepared while checking whether execution can be
/// skipped, to be reused by execution itself if _not_ skipped.
dep_node: Option<DepNode>,
/// Can a `tcx.ensure_ok()` or `tcx.ensure_done()` query return early without
/// actually trying to execute?
enum EnsureCanSkip {
Yes,
// We may have created a `DepNode` while determining whether we can skip.
No(Option<DepNode>),
Comment on lines +579 to +580
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I'd prefer a named field here (e.g. dep_node), especially since the field's meaning is already non-obvious enough to require a comment.

(In general I think positional enum fields are bad news most of the time, if their meaning isn't overwhelmingly obvious.)

}

/// Checks whether a `tcx.ensure_ok()` or `tcx.ensure_done()` query call can
Expand All @@ -597,7 +595,7 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
) -> EnsureCanSkip {
// Queries with `eval_always` should never skip execution.
if query.eval_always {
return EnsureCanSkip { skip_execution: false, dep_node: None };
return EnsureCanSkip::No(None);
}

// Ensuring an anonymous query makes no sense
Expand All @@ -613,7 +611,7 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
// DepNodeIndex. We must invoke the query itself. The performance cost
// this introduces should be negligible as we'll immediately hit the
// in-memory cache, or another query down the line will.
return EnsureCanSkip { skip_execution: false, dep_node: Some(dep_node) };
return EnsureCanSkip::No(Some(dep_node));
}
Some((serialized_dep_node_index, dep_node_index)) => {
tcx.dep_graph.read_index(dep_node_index);
Expand All @@ -627,14 +625,17 @@ fn check_if_ensure_can_skip_execution<'tcx, C: QueryCache>(
// In ensure-ok mode, we can skip execution for this key if the node
// is green. It must have succeeded in the previous session, and
// therefore would succeed in the current session if executed.
EnsureCanSkip { skip_execution: true, dep_node: None }
EnsureCanSkip::Yes
}
EnsureMode::Done => {
// In ensure-done mode, we can only skip execution for this key if
// there's a disk-cached value available to load later if needed,
// which guarantees the query provider will never run for this key.
let is_loadable = (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index);
EnsureCanSkip { skip_execution: is_loadable, dep_node: Some(dep_node) }
if (query.is_loadable_from_disk_fn)(tcx, key, serialized_dep_node_index) {
EnsureCanSkip::Yes
} else {
EnsureCanSkip::No(Some(dep_node))
}
}
}
}
Expand Down Expand Up @@ -669,16 +670,13 @@ pub(super) fn execute_query_incr_inner<'tcx, C: QueryCache>(
// This might have the side-effect of creating a suitable DepNode, which
// we should reuse for execution instead of creating a new one.
let dep_node: Option<DepNode> = match mode {
QueryMode::Get => None,
QueryMode::Ensure { ensure_mode } => {
let EnsureCanSkip { skip_execution, dep_node } =
check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode);
if skip_execution {
// Return early to skip execution.
return None;
match check_if_ensure_can_skip_execution(query, tcx, key, ensure_mode) {
EnsureCanSkip::Yes => return None,
EnsureCanSkip::No(dep_node) => dep_node,
}
dep_node
}
QueryMode::Get => None,
};

let (result, dep_node_index) =
Expand Down
Loading