Skip to content

Commit d21e4d8

Browse files
Actually cache goals
1 parent 67698aa commit d21e4d8

File tree

3 files changed

+65
-70
lines changed

3 files changed

+65
-70
lines changed

compiler/rustc_middle/src/ty/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use crate::mir::{
1717
};
1818
use crate::thir::Thir;
1919
use crate::traits;
20+
use crate::traits::solve;
2021
use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
2122
use crate::ty::query::{self, TyCtxtAt};
2223
use crate::ty::{
@@ -537,6 +538,9 @@ pub struct GlobalCtxt<'tcx> {
537538
/// Merge this with `selection_cache`?
538539
pub evaluation_cache: traits::EvaluationCache<'tcx>,
539540

541+
/// Caches the results of goal evaluation in the new solver.
542+
pub new_solver_evaluation_cache: solve::EvaluationCache<'tcx>,
543+
540544
/// Data layout specification for the current target.
541545
pub data_layout: TargetDataLayout,
542546

@@ -712,6 +716,7 @@ impl<'tcx> TyCtxt<'tcx> {
712716
pred_rcache: Default::default(),
713717
selection_cache: Default::default(),
714718
evaluation_cache: Default::default(),
719+
new_solver_evaluation_cache: Default::default(),
715720
data_layout,
716721
alloc_map: Lock::new(interpret::AllocMap::new()),
717722
}

compiler/rustc_trait_selection/src/solve/search_graph/cache.rs

-25
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@
88
//!
99
//! FIXME(@lcnr): Write that section, feel free to ping me if you need help here
1010
//! before then or if I still haven't done that before January 2023.
11-
use super::overflow::OverflowData;
1211
use super::StackDepth;
1312
use rustc_data_structures::fx::FxHashMap;
1413
use rustc_index::vec::IndexVec;
1514
use rustc_middle::traits::solve::{CanonicalGoal, QueryResult};
16-
use rustc_middle::ty::TyCtxt;
1715

1816
rustc_index::newtype_index! {
1917
pub struct EntryIndex {}
@@ -98,26 +96,3 @@ impl<'tcx> ProvisionalCache<'tcx> {
9896
self.entries[entry_index].response
9997
}
10098
}
101-
102-
pub(super) fn try_move_finished_goal_to_global_cache<'tcx>(
103-
tcx: TyCtxt<'tcx>,
104-
overflow_data: &mut OverflowData,
105-
stack: &IndexVec<super::StackDepth, super::StackElem<'tcx>>,
106-
goal: CanonicalGoal<'tcx>,
107-
response: QueryResult<'tcx>,
108-
) {
109-
// We move goals to the global cache if we either did not hit an overflow or if it's
110-
// the root goal as that will now always hit the same overflow limit.
111-
//
112-
// NOTE: We cannot move any non-root goals to the global cache even if their final result
113-
// isn't impacted by the overflow as that goal still has unstable query dependencies
114-
// because it didn't go its full depth.
115-
//
116-
// FIXME(@lcnr): We could still cache subtrees which are not impacted by overflow though.
117-
// Tracking that info correctly isn't trivial, so I haven't implemented it for now.
118-
let should_cache_globally = !overflow_data.did_overflow() || stack.is_empty();
119-
if should_cache_globally {
120-
// FIXME: move the provisional entry to the global cache.
121-
let _ = (tcx, goal, response);
122-
}
123-
}

compiler/rustc_trait_selection/src/solve/search_graph/mod.rs

+60-45
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ pub(super) use crate::solve::search_graph::overflow::OverflowHandler;
66
use cache::ProvisionalCache;
77
use overflow::OverflowData;
88
use rustc_index::vec::IndexVec;
9+
use rustc_middle::dep_graph::DepKind;
910
use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
1011
use rustc_middle::ty::TyCtxt;
1112
use std::{collections::hash_map::Entry, mem};
@@ -139,10 +140,9 @@ impl<'tcx> SearchGraph<'tcx> {
139140
/// updated the provisional cache and we have to recompute the current goal.
140141
///
141142
/// FIXME: Refer to the rustc-dev-guide entry once it exists.
142-
#[instrument(level = "debug", skip(self, tcx, actual_goal), ret)]
143+
#[instrument(level = "debug", skip(self, actual_goal), ret)]
143144
fn try_finalize_goal(
144145
&mut self,
145-
tcx: TyCtxt<'tcx>,
146146
actual_goal: CanonicalGoal<'tcx>,
147147
response: QueryResult<'tcx>,
148148
) -> bool {
@@ -176,72 +176,87 @@ impl<'tcx> SearchGraph<'tcx> {
176176
self.stack.push(StackElem { goal, has_been_used: false });
177177
false
178178
} else {
179-
self.try_move_finished_goal_to_global_cache(tcx, stack_elem);
180179
true
181180
}
182181
}
183182

184-
fn try_move_finished_goal_to_global_cache(
183+
pub(super) fn with_new_goal(
185184
&mut self,
186185
tcx: TyCtxt<'tcx>,
187-
stack_elem: StackElem<'tcx>,
188-
) {
189-
let StackElem { goal, .. } = stack_elem;
186+
canonical_goal: CanonicalGoal<'tcx>,
187+
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
188+
) -> QueryResult<'tcx> {
189+
if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) {
190+
return result;
191+
}
192+
193+
match self.try_push_stack(tcx, canonical_goal) {
194+
Ok(()) => {}
195+
// Our goal is already on the stack, eager return.
196+
Err(response) => return response,
197+
}
198+
199+
// This is for global caching, so we properly track query dependencies.
200+
// Everything that affects the `Result` should be performed within this
201+
// `with_anon_task` closure.
202+
let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
203+
self.repeat_while_none(
204+
|this| {
205+
let result = this.deal_with_overflow(tcx, canonical_goal);
206+
let _ = this.stack.pop().unwrap();
207+
result
208+
},
209+
|this| {
210+
let result = loop_body(this);
211+
this.try_finalize_goal(canonical_goal, result).then(|| result)
212+
},
213+
)
214+
});
215+
190216
let cache = &mut self.provisional_cache;
191-
let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
217+
let provisional_entry_index = *cache.lookup_table.get(&canonical_goal).unwrap();
192218
let provisional_entry = &mut cache.entries[provisional_entry_index];
193219
let depth = provisional_entry.depth;
194220

195221
// If not, we're done with this goal.
196222
//
197223
// Check whether that this goal doesn't depend on a goal deeper on the stack
198-
// and if so, move it and all nested goals to the global cache.
224+
// and if so, move it to the global cache.
199225
//
200226
// Note that if any nested goal were to depend on something deeper on the stack,
201227
// this would have also updated the depth of the current goal.
202228
if depth == self.stack.next_index() {
203-
for (i, entry) in cache.entries.drain_enumerated(provisional_entry_index.index()..) {
229+
// If the current goal is the head of a cycle, we drop all other
230+
// cycle participants without moving them to the global cache.
231+
let other_cycle_participants = provisional_entry_index.index() + 1;
232+
for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) {
204233
let actual_index = cache.lookup_table.remove(&entry.goal);
205234
debug_assert_eq!(Some(i), actual_index);
206235
debug_assert!(entry.depth == depth);
207-
cache::try_move_finished_goal_to_global_cache(
208-
tcx,
209-
&mut self.overflow_data,
210-
&self.stack,
211-
entry.goal,
212-
entry.response,
213-
);
214236
}
215-
}
216-
}
217237

218-
pub(super) fn with_new_goal(
219-
&mut self,
220-
tcx: TyCtxt<'tcx>,
221-
canonical_goal: CanonicalGoal<'tcx>,
222-
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
223-
) -> QueryResult<'tcx> {
224-
match self.try_push_stack(tcx, canonical_goal) {
225-
Ok(()) => {}
226-
// Our goal is already on the stack, eager return.
227-
Err(response) => return response,
238+
let current_goal = cache.entries.pop().unwrap();
239+
let actual_index = cache.lookup_table.remove(&current_goal.goal);
240+
debug_assert_eq!(Some(provisional_entry_index), actual_index);
241+
debug_assert!(current_goal.depth == depth);
242+
243+
// We move the root goal to the global cache if we either did not hit an overflow or if it's
244+
// the root goal as that will now always hit the same overflow limit.
245+
//
246+
// NOTE: We cannot move any non-root goals to the global cache. When replaying the root goal's
247+
// dependencies, our non-root goal may no longer appear as child of the root goal.
248+
//
249+
// See https://github.com/rust-lang/rust/pull/108071 for some additional context.
250+
let should_cache_globally = !self.overflow_data.did_overflow() || self.stack.is_empty();
251+
if should_cache_globally {
252+
tcx.new_solver_evaluation_cache.insert(
253+
current_goal.goal,
254+
dep_node,
255+
current_goal.response,
256+
);
257+
}
228258
}
229259

230-
self.repeat_while_none(
231-
|this| {
232-
let result = this.deal_with_overflow(tcx, canonical_goal);
233-
let stack_elem = this.stack.pop().unwrap();
234-
this.try_move_finished_goal_to_global_cache(tcx, stack_elem);
235-
result
236-
},
237-
|this| {
238-
let result = loop_body(this);
239-
if this.try_finalize_goal(tcx, canonical_goal, result) {
240-
Some(result)
241-
} else {
242-
None
243-
}
244-
},
245-
)
260+
result
246261
}
247262
}

0 commit comments

Comments
 (0)