Skip to content

Commit ee50590

Browse files
committed
Auto merge of #69295 - ecstatic-morse:unified-dataflow-generators, r=tmandry
Use new dataflow framework for generators #65672 introduced a new dataflow framework that can handle arbitrarily complex transfer functions as well as ones expressed as a series of gen/kill operations. This PR ports the analyses used to implement generators to the new framework so that we can remove the old one. See #68241 for a prior example of this. The new framework has some superficial API changes, but this shouldn't alter the generator passes in any way. r? @tmandry
2 parents d905134 + 21cd1fe commit ee50590

File tree

5 files changed

+159
-158
lines changed

5 files changed

+159
-158
lines changed

src/librustc_mir/dataflow/generic/mod.rs

+18-11
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,24 @@ where
7575
pub fn entry_set_for_block(&self, block: BasicBlock) -> &BitSet<A::Idx> {
7676
&self.entry_sets[block]
7777
}
78+
79+
pub fn visit_with(
80+
&self,
81+
body: &'mir mir::Body<'tcx>,
82+
blocks: impl IntoIterator<Item = BasicBlock>,
83+
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet<A::Idx>>,
84+
) {
85+
visit_results(body, blocks, self, vis)
86+
}
87+
88+
pub fn visit_in_rpo_with(
89+
&self,
90+
body: &'mir mir::Body<'tcx>,
91+
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet<A::Idx>>,
92+
) {
93+
let blocks = mir::traversal::reverse_postorder(body);
94+
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
95+
}
7896
}
7997

8098
/// Define the domain of a dataflow problem.
@@ -433,16 +451,5 @@ impl<T: Idx> GenKill<T> for BitSet<T> {
433451
}
434452
}
435453

436-
// For compatibility with old framework
437-
impl<T: Idx> GenKill<T> for crate::dataflow::GenKillSet<T> {
438-
fn gen(&mut self, elem: T) {
439-
self.gen(elem);
440-
}
441-
442-
fn kill(&mut self, elem: T) {
443-
self.kill(elem);
444-
}
445-
}
446-
447454
#[cfg(test)]
448455
mod tests;

src/librustc_mir/dataflow/impls/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use crate::util::elaborate_drops::DropFlagState;
1414

1515
use super::generic::{AnalysisDomain, GenKill, GenKillAnalysis};
1616
use super::move_paths::{HasMoveData, InitIndex, InitKind, LookupResult, MoveData, MovePathIndex};
17-
use super::{BottomValue, GenKillSet};
17+
use super::BottomValue;
1818

1919
use super::drop_flag_effects_for_function_entry;
2020
use super::drop_flag_effects_for_location;

src/librustc_mir/dataflow/impls/storage_liveness.rs

+104-87
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,68 @@
11
pub use super::*;
22

3-
use crate::dataflow::generic::{Results, ResultsRefCursor};
4-
use crate::dataflow::BitDenotation;
5-
use crate::dataflow::MaybeBorrowedLocals;
3+
use crate::dataflow::generic::{self as dataflow, GenKill, Results, ResultsRefCursor};
4+
use crate::dataflow::BottomValue;
65
use rustc::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
76
use rustc::mir::*;
87
use std::cell::RefCell;
98

109
#[derive(Copy, Clone)]
11-
pub struct MaybeStorageLive<'a, 'tcx> {
12-
body: &'a Body<'tcx>,
13-
}
10+
pub struct MaybeStorageLive;
1411

15-
impl<'a, 'tcx> MaybeStorageLive<'a, 'tcx> {
16-
pub fn new(body: &'a Body<'tcx>) -> Self {
17-
MaybeStorageLive { body }
18-
}
12+
impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive {
13+
type Idx = Local;
1914

20-
pub fn body(&self) -> &Body<'tcx> {
21-
self.body
22-
}
23-
}
15+
const NAME: &'static str = "maybe_storage_live";
2416

25-
impl<'a, 'tcx> BitDenotation<'tcx> for MaybeStorageLive<'a, 'tcx> {
26-
type Idx = Local;
27-
fn name() -> &'static str {
28-
"maybe_storage_live"
29-
}
30-
fn bits_per_block(&self) -> usize {
31-
self.body.local_decls.len()
17+
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
18+
body.local_decls.len()
3219
}
3320

34-
fn start_block_effect(&self, on_entry: &mut BitSet<Local>) {
21+
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
3522
// The resume argument is live on function entry (we don't care about
3623
// the `self` argument)
37-
for arg in self.body.args_iter().skip(1) {
24+
for arg in body.args_iter().skip(1) {
3825
on_entry.insert(arg);
3926
}
4027
}
28+
}
4129

42-
fn statement_effect(&self, trans: &mut GenKillSet<Local>, loc: Location) {
43-
let stmt = &self.body[loc.block].statements[loc.statement_index];
44-
30+
impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive {
31+
fn statement_effect(
32+
&self,
33+
trans: &mut impl GenKill<Self::Idx>,
34+
stmt: &mir::Statement<'tcx>,
35+
_: Location,
36+
) {
4537
match stmt.kind {
4638
StatementKind::StorageLive(l) => trans.gen(l),
4739
StatementKind::StorageDead(l) => trans.kill(l),
4840
_ => (),
4941
}
5042
}
5143

52-
fn terminator_effect(&self, _trans: &mut GenKillSet<Local>, _loc: Location) {
44+
fn terminator_effect(
45+
&self,
46+
_trans: &mut impl GenKill<Self::Idx>,
47+
_: &mir::Terminator<'tcx>,
48+
_: Location,
49+
) {
5350
// Terminators have no effect
5451
}
5552

56-
fn propagate_call_return(
53+
fn call_return_effect(
5754
&self,
58-
_in_out: &mut BitSet<Local>,
59-
_call_bb: mir::BasicBlock,
60-
_dest_bb: mir::BasicBlock,
61-
_dest_place: &mir::Place<'tcx>,
55+
_trans: &mut impl GenKill<Self::Idx>,
56+
_block: BasicBlock,
57+
_func: &mir::Operand<'tcx>,
58+
_args: &[mir::Operand<'tcx>],
59+
_return_place: &mir::Place<'tcx>,
6260
) {
6361
// Nothing to do when a call returns successfully
6462
}
6563
}
6664

67-
impl<'a, 'tcx> BottomValue for MaybeStorageLive<'a, 'tcx> {
65+
impl BottomValue for MaybeStorageLive {
6866
/// bottom = dead
6967
const BOTTOM_VALUE: bool = false;
7068
}
@@ -73,60 +71,62 @@ type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorro
7371

7472
/// Dataflow analysis that determines whether each local requires storage at a
7573
/// given location; i.e. whether its storage can go away without being observed.
76-
pub struct RequiresStorage<'mir, 'tcx> {
74+
pub struct MaybeRequiresStorage<'mir, 'tcx> {
7775
body: ReadOnlyBodyAndCache<'mir, 'tcx>,
7876
borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
7977
}
8078

81-
impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
79+
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
8280
pub fn new(
8381
body: ReadOnlyBodyAndCache<'mir, 'tcx>,
8482
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
8583
) -> Self {
86-
RequiresStorage {
84+
MaybeRequiresStorage {
8785
body,
8886
borrowed_locals: RefCell::new(ResultsRefCursor::new(*body, borrowed_locals)),
8987
}
9088
}
91-
92-
pub fn body(&self) -> &Body<'tcx> {
93-
&self.body
94-
}
9589
}
9690

97-
impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
91+
impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
9892
type Idx = Local;
99-
fn name() -> &'static str {
100-
"requires_storage"
101-
}
102-
fn bits_per_block(&self) -> usize {
103-
self.body.local_decls.len()
93+
94+
const NAME: &'static str = "requires_storage";
95+
96+
fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize {
97+
body.local_decls.len()
10498
}
10599

106-
fn start_block_effect(&self, on_entry: &mut BitSet<Local>) {
100+
fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut BitSet<Self::Idx>) {
107101
// The resume argument is live on function entry (we don't care about
108102
// the `self` argument)
109-
for arg in self.body.args_iter().skip(1) {
103+
for arg in body.args_iter().skip(1) {
110104
on_entry.insert(arg);
111105
}
112106
}
107+
}
113108

114-
fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
115-
let stmt = &self.body[loc.block].statements[loc.statement_index];
116-
109+
impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> {
110+
fn before_statement_effect(
111+
&self,
112+
trans: &mut impl GenKill<Self::Idx>,
113+
stmt: &mir::Statement<'tcx>,
114+
loc: Location,
115+
) {
117116
// If a place is borrowed in a statement, it needs storage for that statement.
118-
self.borrowed_locals.borrow().analysis().statement_effect(sets, stmt, loc);
117+
self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
119118

120-
// If a place is assigned to in a statement, it needs storage for that statement.
121119
match &stmt.kind {
122-
StatementKind::StorageDead(l) => sets.kill(*l),
120+
StatementKind::StorageDead(l) => trans.kill(*l),
121+
122+
// If a place is assigned to in a statement, it needs storage for that statement.
123123
StatementKind::Assign(box (place, _))
124124
| StatementKind::SetDiscriminant { box place, .. } => {
125-
sets.gen(place.local);
125+
trans.gen(place.local);
126126
}
127-
StatementKind::InlineAsm(box InlineAsm { outputs, .. }) => {
128-
for place in &**outputs {
129-
sets.gen(place.local);
127+
StatementKind::InlineAsm(asm) => {
128+
for place in &*asm.outputs {
129+
trans.gen(place.local);
130130
}
131131
}
132132

@@ -140,22 +140,30 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
140140
}
141141
}
142142

143-
fn statement_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
143+
fn statement_effect(
144+
&self,
145+
trans: &mut impl GenKill<Self::Idx>,
146+
_: &mir::Statement<'tcx>,
147+
loc: Location,
148+
) {
144149
// If we move from a place then only stops needing storage *after*
145150
// that statement.
146-
self.check_for_move(sets, loc);
151+
self.check_for_move(trans, loc);
147152
}
148153

149-
fn before_terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
150-
let terminator = self.body[loc.block].terminator();
151-
154+
fn before_terminator_effect(
155+
&self,
156+
trans: &mut impl GenKill<Self::Idx>,
157+
terminator: &mir::Terminator<'tcx>,
158+
loc: Location,
159+
) {
152160
// If a place is borrowed in a terminator, it needs storage for that terminator.
153-
self.borrowed_locals.borrow().analysis().terminator_effect(sets, terminator, loc);
161+
self.borrowed_locals.borrow().analysis().terminator_effect(trans, terminator, loc);
154162

155163
match &terminator.kind {
156-
TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. }
157-
| TerminatorKind::Yield { resume_arg: Place { local, .. }, .. } => {
158-
sets.gen(*local);
164+
TerminatorKind::Call { destination: Some((place, _)), .. }
165+
| TerminatorKind::Yield { resume_arg: place, .. } => {
166+
trans.gen(place.local);
159167
}
160168

161169
// Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -176,14 +184,19 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
176184
}
177185
}
178186

179-
fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
180-
match &self.body[loc.block].terminator().kind {
187+
fn terminator_effect(
188+
&self,
189+
trans: &mut impl GenKill<Self::Idx>,
190+
terminator: &mir::Terminator<'tcx>,
191+
loc: Location,
192+
) {
193+
match &terminator.kind {
181194
// For call terminators the destination requires storage for the call
182195
// and after the call returns successfully, but not after a panic.
183196
// Since `propagate_call_unwind` doesn't exist, we have to kill the
184-
// destination here, and then gen it again in `propagate_call_return`.
185-
TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } => {
186-
sets.kill(*local);
197+
// destination here, and then gen it again in `call_return_effect`.
198+
TerminatorKind::Call { destination: Some((place, _)), .. } => {
199+
trans.kill(place.local);
187200
}
188201

189202
// Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -204,45 +217,49 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
204217
| TerminatorKind::Unreachable => {}
205218
}
206219

207-
self.check_for_move(sets, loc);
220+
self.check_for_move(trans, loc);
208221
}
209222

210-
fn propagate_call_return(
223+
fn call_return_effect(
211224
&self,
212-
in_out: &mut BitSet<Local>,
213-
_call_bb: mir::BasicBlock,
214-
_dest_bb: mir::BasicBlock,
215-
dest_place: &mir::Place<'tcx>,
225+
trans: &mut impl GenKill<Self::Idx>,
226+
_block: BasicBlock,
227+
_func: &mir::Operand<'tcx>,
228+
_args: &[mir::Operand<'tcx>],
229+
return_place: &mir::Place<'tcx>,
216230
) {
217-
in_out.insert(dest_place.local);
231+
trans.gen(return_place.local);
218232
}
219233
}
220234

221-
impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
235+
impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> {
222236
/// Kill locals that are fully moved and have not been borrowed.
223-
fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
224-
let mut visitor = MoveVisitor { sets, borrowed_locals: &self.borrowed_locals };
237+
fn check_for_move(&self, trans: &mut impl GenKill<Local>, loc: Location) {
238+
let mut visitor = MoveVisitor { trans, borrowed_locals: &self.borrowed_locals };
225239
visitor.visit_location(self.body, loc);
226240
}
227241
}
228242

229-
impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
243+
impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> {
230244
/// bottom = dead
231245
const BOTTOM_VALUE: bool = false;
232246
}
233247

234-
struct MoveVisitor<'a, 'mir, 'tcx> {
248+
struct MoveVisitor<'a, 'mir, 'tcx, T> {
235249
borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
236-
sets: &'a mut GenKillSet<Local>,
250+
trans: &'a mut T,
237251
}
238252

239-
impl<'a, 'mir: 'a, 'tcx> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx> {
253+
impl<'a, 'mir, 'tcx, T> Visitor<'tcx> for MoveVisitor<'a, 'mir, 'tcx, T>
254+
where
255+
T: GenKill<Local>,
256+
{
240257
fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
241258
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
242259
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
243260
borrowed_locals.seek_before(loc);
244261
if !borrowed_locals.contains(*local) {
245-
self.sets.kill(*local);
262+
self.trans.kill(*local);
246263
}
247264
}
248265
}

src/librustc_mir/dataflow/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ pub use self::impls::DefinitelyInitializedPlaces;
2525
pub use self::impls::EverInitializedPlaces;
2626
pub use self::impls::{MaybeBorrowedLocals, MaybeMutBorrowedLocals};
2727
pub use self::impls::{MaybeInitializedPlaces, MaybeUninitializedPlaces};
28-
pub use self::impls::{MaybeStorageLive, RequiresStorage};
28+
pub use self::impls::{MaybeRequiresStorage, MaybeStorageLive};
2929

3030
use self::move_paths::MoveData;
3131

0 commit comments

Comments
 (0)