Auto merge of #108293 - Jarcho:mut_analyses, r=eholk

Take MIR dataflow analyses by mutable reference

The main motivation here is any analysis requiring dynamically sized scratch memory to work. One concrete example would be pointer target tracking, where tracking the results of a dereference can result in multiple possible targets. This leads to processing multi-level dereferences requiring the ability to handle a changing number of potential targets per step. A (simplified) function for this would be `fn apply_deref(potential_targets: &mut Vec<Target>)` which would use the scratch space contained in the analysis to send arguments and receive the results.

The alternative to this would be to wrap everything in a `RefCell`, which is what `MaybeRequiresStorage` currently does. This comes with a small perf cost and loses the compiler's guarantee that we don't try to take multiple borrows at the same time.

For the implementation:
* `AnalysisResults` is an unfortunate requirement to avoid an unconstrained type parameter error.
* `CloneAnalysis` could just be `Clone` instead, but that would result in more work than is required to have multiple cursors over the same result set.
* `ResultsVisitor` now takes the results type on in each function as there's no other way to have access to the analysis without cloning it. This could use an associated type rather than a type parameter, but the current approach makes it easier to not care about the type when it's not necessary.
* `MaybeRequiresStorage` now no longer uses a `RefCell`, but the graphviz formatter now does. It could be removed, but that would require even more changes and doesn't really seem necessary.
This commit is contained in:
bors 2023-06-08 23:58:44 +00:00
commit 68c8fdaac0
19 changed files with 491 additions and 288 deletions

View file

@ -597,16 +597,15 @@ fn locals_live_across_suspend_points<'tcx>(
let borrowed_locals_results =
MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
let mut borrowed_locals_cursor =
rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
let mut borrowed_locals_cursor = borrowed_locals_results.cloned_results_cursor(body_ref);
// Calculate the MIR locals that we actually need to keep storage around
// for.
let requires_storage_results = MaybeRequiresStorage::new(body, &borrowed_locals_results)
.into_engine(tcx, body_ref)
.iterate_to_fixpoint();
let mut requires_storage_cursor =
rustc_mir_dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
let mut requires_storage_results =
MaybeRequiresStorage::new(borrowed_locals_results.cloned_results_cursor(body))
.into_engine(tcx, body_ref)
.iterate_to_fixpoint();
let mut requires_storage_cursor = requires_storage_results.as_results_cursor(body_ref);
// Calculate the liveness of MIR locals ignoring borrows.
let mut liveness = MaybeLiveLocals
@ -747,7 +746,7 @@ fn compute_storage_conflicts<'mir, 'tcx>(
body: &'mir Body<'tcx>,
saved_locals: &GeneratorSavedLocals,
always_live_locals: BitSet<Local>,
requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'mir, 'tcx>>,
mut requires_storage: rustc_mir_dataflow::Results<'tcx, MaybeRequiresStorage<'_, 'mir, 'tcx>>,
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
assert_eq!(body.local_decls.len(), saved_locals.domain_size());
@ -802,13 +801,14 @@ struct StorageConflictVisitor<'mir, 'tcx, 's> {
local_conflicts: BitMatrix<Local, Local>,
}
impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
impl<'mir, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx, R>
for StorageConflictVisitor<'mir, 'tcx, '_>
{
type FlowState = BitSet<Local>;
fn visit_statement_before_primary_effect(
&mut self,
_results: &R,
state: &Self::FlowState,
_statement: &'mir Statement<'tcx>,
loc: Location,
@ -818,6 +818,7 @@ impl<'mir, 'tcx> rustc_mir_dataflow::ResultsVisitor<'mir, 'tcx>
fn visit_terminator_before_primary_effect(
&mut self,
_results: &R,
state: &Self::FlowState,
_terminator: &'mir Terminator<'tcx>,
loc: Location,