Skip to content

Commit 68c8fda

Browse files
committed
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.
2 parents 8b35c0b + eaddc37 commit 68c8fda

File tree

19 files changed

+491
-288
lines changed

19 files changed

+491
-288
lines changed

compiler/rustc_borrowck/src/dataflow.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ macro_rules! impl_visitable {
5959
}
6060

6161
fn reconstruct_before_statement_effect(
62-
&self,
62+
&mut self,
6363
state: &mut Self::FlowState,
6464
stmt: &mir::Statement<'tcx>,
6565
loc: Location,
@@ -69,7 +69,7 @@ macro_rules! impl_visitable {
6969
}
7070

7171
fn reconstruct_statement_effect(
72-
&self,
72+
&mut self,
7373
state: &mut Self::FlowState,
7474
stmt: &mir::Statement<'tcx>,
7575
loc: Location,
@@ -79,7 +79,7 @@ macro_rules! impl_visitable {
7979
}
8080

8181
fn reconstruct_before_terminator_effect(
82-
&self,
82+
&mut self,
8383
state: &mut Self::FlowState,
8484
term: &mir::Terminator<'tcx>,
8585
loc: Location,
@@ -89,7 +89,7 @@ macro_rules! impl_visitable {
8989
}
9090

9191
fn reconstruct_terminator_effect(
92-
&self,
92+
&mut self,
9393
state: &mut Self::FlowState,
9494
term: &mir::Terminator<'tcx>,
9595
loc: Location,
@@ -343,7 +343,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
343343
type Idx = BorrowIndex;
344344

345345
fn before_statement_effect(
346-
&self,
346+
&mut self,
347347
trans: &mut impl GenKill<Self::Idx>,
348348
_statement: &mir::Statement<'tcx>,
349349
location: Location,
@@ -352,7 +352,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
352352
}
353353

354354
fn statement_effect(
355-
&self,
355+
&mut self,
356356
trans: &mut impl GenKill<Self::Idx>,
357357
stmt: &mir::Statement<'tcx>,
358358
location: Location,
@@ -400,7 +400,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
400400
}
401401

402402
fn before_terminator_effect(
403-
&self,
403+
&mut self,
404404
trans: &mut impl GenKill<Self::Idx>,
405405
_terminator: &mir::Terminator<'tcx>,
406406
location: Location,
@@ -409,7 +409,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
409409
}
410410

411411
fn terminator_effect(
412-
&self,
412+
&mut self,
413413
trans: &mut impl GenKill<Self::Idx>,
414414
terminator: &mir::Terminator<'tcx>,
415415
_location: Location,
@@ -426,7 +426,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
426426
}
427427

428428
fn call_return_effect(
429-
&self,
429+
&mut self,
430430
_trans: &mut impl GenKill<Self::Idx>,
431431
_block: mir::BasicBlock,
432432
_return_places: CallReturnPlaces<'_, 'tcx>,

compiler/rustc_borrowck/src/lib.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ fn do_mir_borrowck<'tcx>(
368368
// Compute and report region errors, if any.
369369
mbcx.report_region_errors(nll_errors);
370370

371-
let results = BorrowckResults {
371+
let mut results = BorrowckResults {
372372
ever_inits: flow_ever_inits,
373373
uninits: flow_uninits,
374374
borrows: flow_borrows,
@@ -379,7 +379,7 @@ fn do_mir_borrowck<'tcx>(
379379
rustc_mir_dataflow::visit_results(
380380
body,
381381
traversal::reverse_postorder(body).map(|(bb, _)| bb),
382-
&results,
382+
&mut results,
383383
&mut mbcx,
384384
);
385385

@@ -598,11 +598,12 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
598598
// 2. loans made in overlapping scopes do not conflict
599599
// 3. assignments do not affect things loaned out as immutable
600600
// 4. moves do not affect things loaned out in any way
601-
impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtxt<'cx, 'tcx> {
601+
impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorrowckCtxt<'cx, 'tcx> {
602602
type FlowState = Flows<'cx, 'tcx>;
603603

604604
fn visit_statement_before_primary_effect(
605605
&mut self,
606+
_results: &R,
606607
flow_state: &Flows<'cx, 'tcx>,
607608
stmt: &'cx Statement<'tcx>,
608609
location: Location,
@@ -672,6 +673,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
672673

673674
fn visit_terminator_before_primary_effect(
674675
&mut self,
676+
_results: &R,
675677
flow_state: &Flows<'cx, 'tcx>,
676678
term: &'cx Terminator<'tcx>,
677679
loc: Location,
@@ -782,6 +784,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
782784

783785
fn visit_terminator_after_primary_effect(
784786
&mut self,
787+
_results: &R,
785788
flow_state: &Flows<'cx, 'tcx>,
786789
term: &'cx Terminator<'tcx>,
787790
loc: Location,

compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ where
337337
Q: Qualif,
338338
{
339339
fn apply_statement_effect(
340-
&self,
340+
&mut self,
341341
state: &mut Self::Domain,
342342
statement: &mir::Statement<'tcx>,
343343
location: Location,
@@ -346,7 +346,7 @@ where
346346
}
347347

348348
fn apply_terminator_effect(
349-
&self,
349+
&mut self,
350350
state: &mut Self::Domain,
351351
terminator: &mir::Terminator<'tcx>,
352352
location: Location,
@@ -355,7 +355,7 @@ where
355355
}
356356

357357
fn apply_call_return_effect(
358-
&self,
358+
&mut self,
359359
state: &mut Self::Domain,
360360
block: BasicBlock,
361361
return_places: CallReturnPlaces<'_, 'tcx>,

compiler/rustc_mir_dataflow/src/framework/cursor.rs

+97-15
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,60 @@
11
//! Random access inspection of the results of a dataflow analysis.
22
3-
use crate::framework::BitSetExt;
3+
use crate::{framework::BitSetExt, CloneAnalysis};
44

5-
use std::borrow::Borrow;
5+
use std::borrow::{Borrow, BorrowMut};
66
use std::cmp::Ordering;
77

88
#[cfg(debug_assertions)]
99
use rustc_index::bit_set::BitSet;
1010
use rustc_middle::mir::{self, BasicBlock, Location};
1111

12-
use super::{Analysis, Direction, Effect, EffectIndex, Results};
12+
use super::{Analysis, Direction, Effect, EffectIndex, EntrySets, Results, ResultsCloned};
13+
14+
// `AnalysisResults` is needed as an impl such as the following has an unconstrained type
15+
// parameter:
16+
// ```
17+
// impl<'tcx, A, E, R> ResultsCursor<'_, 'tcx, A, R>
18+
// where
19+
// A: Analysis<'tcx>,
20+
// E: Borrow<EntrySets<'tcx, A>>,
21+
// R: Results<'tcx, A, E>,
22+
// {}
23+
// ```
24+
25+
/// A type representing the analysis results consumed by a `ResultsCursor`.
26+
pub trait AnalysisResults<'tcx, A>: BorrowMut<Results<'tcx, A, Self::EntrySets>>
27+
where
28+
A: Analysis<'tcx>,
29+
{
30+
/// The type containing the entry sets for this `Results` type.
31+
///
32+
/// Should be either `EntrySets<'tcx, A>` or `&EntrySets<'tcx, A>`.
33+
type EntrySets: Borrow<EntrySets<'tcx, A>>;
34+
}
35+
impl<'tcx, A, E> AnalysisResults<'tcx, A> for Results<'tcx, A, E>
36+
where
37+
A: Analysis<'tcx>,
38+
E: Borrow<EntrySets<'tcx, A>>,
39+
{
40+
type EntrySets = E;
41+
}
42+
impl<'a, 'tcx, A, E> AnalysisResults<'tcx, A> for &'a mut Results<'tcx, A, E>
43+
where
44+
A: Analysis<'tcx>,
45+
E: Borrow<EntrySets<'tcx, A>>,
46+
{
47+
type EntrySets = E;
48+
}
1349

1450
/// A `ResultsCursor` that borrows the underlying `Results`.
15-
pub type ResultsRefCursor<'a, 'mir, 'tcx, A> = ResultsCursor<'mir, 'tcx, A, &'a Results<'tcx, A>>;
51+
pub type ResultsRefCursor<'res, 'mir, 'tcx, A> =
52+
ResultsCursor<'mir, 'tcx, A, &'res mut Results<'tcx, A>>;
53+
54+
/// A `ResultsCursor` which uses a cloned `Analysis` while borrowing the underlying `Results`. This
55+
/// allows multiple cursors over the same `Results`.
56+
pub type ResultsClonedCursor<'res, 'mir, 'tcx, A> =
57+
ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>;
1658

1759
/// Allows random access inspection of the results of a dataflow analysis.
1860
///
@@ -45,7 +87,38 @@ where
4587
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
4688
where
4789
A: Analysis<'tcx>,
48-
R: Borrow<Results<'tcx, A>>,
90+
{
91+
/// Returns the dataflow state at the current location.
92+
pub fn get(&self) -> &A::Domain {
93+
&self.state
94+
}
95+
96+
/// Returns the body this analysis was run on.
97+
pub fn body(&self) -> &'mir mir::Body<'tcx> {
98+
self.body
99+
}
100+
101+
/// Unwraps this cursor, returning the underlying `Results`.
102+
pub fn into_results(self) -> R {
103+
self.results
104+
}
105+
}
106+
107+
impl<'res, 'mir, 'tcx, A> ResultsCursor<'mir, 'tcx, A, ResultsCloned<'res, 'tcx, A>>
108+
where
109+
A: Analysis<'tcx> + CloneAnalysis,
110+
{
111+
/// Creates a new cursor over the same `Results`. Note that the cursor's position is *not*
112+
/// copied.
113+
pub fn new_cursor(&self) -> Self {
114+
Self::new(self.body, self.results.reclone_analysis())
115+
}
116+
}
117+
118+
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
119+
where
120+
A: Analysis<'tcx>,
121+
R: AnalysisResults<'tcx, A>,
49122
{
50123
/// Returns a new cursor that can inspect `results`.
51124
pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self {
@@ -74,18 +147,28 @@ where
74147
}
75148

76149
/// Returns the underlying `Results`.
77-
pub fn results(&self) -> &Results<'tcx, A> {
78-
&self.results.borrow()
150+
pub fn results(&mut self) -> &Results<'tcx, A, R::EntrySets> {
151+
self.results.borrow()
152+
}
153+
154+
/// Returns the underlying `Results`.
155+
pub fn mut_results(&mut self) -> &mut Results<'tcx, A, R::EntrySets> {
156+
self.results.borrow_mut()
79157
}
80158

81159
/// Returns the `Analysis` used to generate the underlying `Results`.
82160
pub fn analysis(&self) -> &A {
83161
&self.results.borrow().analysis
84162
}
85163

86-
/// Returns the dataflow state at the current location.
87-
pub fn get(&self) -> &A::Domain {
88-
&self.state
164+
/// Returns the `Analysis` used to generate the underlying `Results`.
165+
pub fn mut_analysis(&mut self) -> &mut A {
166+
&mut self.results.borrow_mut().analysis
167+
}
168+
169+
/// Returns both the dataflow state at the current location and the `Analysis`.
170+
pub fn get_with_analysis(&mut self) -> (&A::Domain, &mut A) {
171+
(&self.state, &mut self.results.borrow_mut().analysis)
89172
}
90173

91174
/// Resets the cursor to hold the entry set for the given basic block.
@@ -97,7 +180,7 @@ where
97180
#[cfg(debug_assertions)]
98181
assert!(self.reachable_blocks.contains(block));
99182

100-
self.state.clone_from(&self.results.borrow().entry_set_for_block(block));
183+
self.state.clone_from(self.results.borrow().entry_set_for_block(block));
101184
self.pos = CursorPosition::block_entry(block);
102185
self.state_needs_reset = false;
103186
}
@@ -186,7 +269,7 @@ where
186269
)
187270
};
188271

189-
let analysis = &self.results.borrow().analysis;
272+
let analysis = &mut self.results.borrow_mut().analysis;
190273
let target_effect_index = effect.at_index(target.statement_index);
191274

192275
A::Direction::apply_effects_in_range(
@@ -205,8 +288,8 @@ where
205288
///
206289
/// This can be used, e.g., to apply the call return effect directly to the cursor without
207290
/// creating an extra copy of the dataflow state.
208-
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&A, &mut A::Domain)) {
209-
f(&self.results.borrow().analysis, &mut self.state);
291+
pub fn apply_custom_effect(&mut self, f: impl FnOnce(&mut A, &mut A::Domain)) {
292+
f(&mut self.results.borrow_mut().analysis, &mut self.state);
210293
self.state_needs_reset = true;
211294
}
212295
}
@@ -215,7 +298,6 @@ impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
215298
where
216299
A: crate::GenKillAnalysis<'tcx>,
217300
A::Domain: BitSetExt<A::Idx>,
218-
R: Borrow<Results<'tcx, A>>,
219301
{
220302
pub fn contains(&self, elem: A::Idx) -> bool {
221303
self.get().contains(elem)

0 commit comments

Comments
 (0)