Skip to content

Commit ecad434

Browse files
Port RequiresStorage to new dataflow framework
1 parent 6d7ce88 commit ecad434

File tree

3 files changed

+97
-100
lines changed

3 files changed

+97
-100
lines changed

src/librustc_mir/dataflow/impls/mod.rs

Lines changed: 1 addition & 1 deletion
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

Lines changed: 69 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ pub struct RequiresStorage<'mir, 'tcx> {
7676
borrowed_locals: RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
7777
}
7878

79-
impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
79+
impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
8080
pub fn new(
8181
body: ReadOnlyBodyAndCache<'mir, 'tcx>,
8282
borrowed_locals: &'mir Results<'tcx, MaybeBorrowedLocals>,
@@ -86,45 +86,47 @@ impl<'mir, 'tcx: 'mir> RequiresStorage<'mir, 'tcx> {
8686
borrowed_locals: RefCell::new(ResultsRefCursor::new(*body, borrowed_locals)),
8787
}
8888
}
89-
90-
pub fn body(&self) -> &Body<'tcx> {
91-
&self.body
92-
}
9389
}
9490

95-
impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
91+
impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for RequiresStorage<'mir, 'tcx> {
9692
type Idx = Local;
97-
fn name() -> &'static str {
98-
"requires_storage"
99-
}
100-
fn bits_per_block(&self) -> usize {
101-
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()
10298
}
10399

104-
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>) {
105101
// The resume argument is live on function entry (we don't care about
106102
// the `self` argument)
107-
for arg in self.body.args_iter().skip(1) {
103+
for arg in body.args_iter().skip(1) {
108104
on_entry.insert(arg);
109105
}
110106
}
107+
}
111108

112-
fn before_statement_effect(&self, sets: &mut GenKillSet<Self::Idx>, loc: Location) {
113-
let stmt = &self.body[loc.block].statements[loc.statement_index];
114-
109+
impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for RequiresStorage<'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+
) {
115116
// If a place is borrowed in a statement, it needs storage for that statement.
116-
self.borrowed_locals.borrow().analysis().statement_effect(sets, stmt, loc);
117+
self.borrowed_locals.borrow().analysis().statement_effect(trans, stmt, loc);
117118

118-
// If a place is assigned to in a statement, it needs storage for that statement.
119119
match &stmt.kind {
120-
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.
121123
StatementKind::Assign(box (place, _))
122124
| StatementKind::SetDiscriminant { box place, .. } => {
123-
sets.gen(place.local);
125+
trans.gen(place.local);
124126
}
125-
StatementKind::InlineAsm(box InlineAsm { outputs, .. }) => {
126-
for place in &**outputs {
127-
sets.gen(place.local);
127+
StatementKind::InlineAsm(asm) => {
128+
for place in &*asm.outputs {
129+
trans.gen(place.local);
128130
}
129131
}
130132

@@ -138,22 +140,30 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
138140
}
139141
}
140142

141-
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+
) {
142149
// If we move from a place then only stops needing storage *after*
143150
// that statement.
144-
self.check_for_move(sets, loc);
151+
self.check_for_move(trans, loc);
145152
}
146153

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

153163
match &terminator.kind {
154-
TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. }
155-
| TerminatorKind::Yield { resume_arg: Place { local, .. }, .. } => {
156-
sets.gen(*local);
164+
TerminatorKind::Call { destination: Some((place, _)), .. }
165+
| TerminatorKind::Yield { resume_arg: place, .. } => {
166+
trans.gen(place.local);
157167
}
158168

159169
// Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -174,14 +184,19 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
174184
}
175185
}
176186

177-
fn terminator_effect(&self, sets: &mut GenKillSet<Local>, loc: Location) {
178-
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 {
179194
// For call terminators the destination requires storage for the call
180195
// and after the call returns successfully, but not after a panic.
181196
// Since `propagate_call_unwind` doesn't exist, we have to kill the
182-
// destination here, and then gen it again in `propagate_call_return`.
183-
TerminatorKind::Call { destination: Some((Place { local, .. }, _)), .. } => {
184-
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);
185200
}
186201

187202
// Nothing to do for these. Match exhaustively so this fails to compile when new
@@ -202,24 +217,25 @@ impl<'mir, 'tcx> BitDenotation<'tcx> for RequiresStorage<'mir, 'tcx> {
202217
| TerminatorKind::Unreachable => {}
203218
}
204219

205-
self.check_for_move(sets, loc);
220+
self.check_for_move(trans, loc);
206221
}
207222

208-
fn propagate_call_return(
223+
fn call_return_effect(
209224
&self,
210-
in_out: &mut BitSet<Local>,
211-
_call_bb: mir::BasicBlock,
212-
_dest_bb: mir::BasicBlock,
213-
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>,
214230
) {
215-
in_out.insert(dest_place.local);
231+
trans.gen(return_place.local);
216232
}
217233
}
218234

219235
impl<'mir, 'tcx> RequiresStorage<'mir, 'tcx> {
220236
/// Kill locals that are fully moved and have not been borrowed.
221-
fn check_for_move(&self, sets: &mut GenKillSet<Local>, loc: Location) {
222-
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 };
223239
visitor.visit_location(self.body, loc);
224240
}
225241
}
@@ -229,18 +245,21 @@ impl<'mir, 'tcx> BottomValue for RequiresStorage<'mir, 'tcx> {
229245
const BOTTOM_VALUE: bool = false;
230246
}
231247

232-
struct MoveVisitor<'a, 'mir, 'tcx> {
248+
struct MoveVisitor<'a, 'mir, 'tcx, T> {
233249
borrowed_locals: &'a RefCell<BorrowedLocalsResults<'mir, 'tcx>>,
234-
sets: &'a mut GenKillSet<Local>,
250+
trans: &'a mut T,
235251
}
236252

237-
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+
{
238257
fn visit_local(&mut self, local: &Local, context: PlaceContext, loc: Location) {
239258
if PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) == context {
240259
let mut borrowed_locals = self.borrowed_locals.borrow_mut();
241260
borrowed_locals.seek_before(loc);
242261
if !borrowed_locals.contains(*local) {
243-
self.sets.kill(*local);
262+
self.trans.kill(*local);
244263
}
245264
}
246265
}

src/librustc_mir/transform/generator.rs

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,7 @@
4949
//! For generators with state 1 (returned) and state 2 (poisoned) it does nothing.
5050
//! Otherwise it drops all the values in scope at the last suspension point.
5151
52-
use crate::dataflow::generic::{Analysis, ResultsCursor};
53-
use crate::dataflow::{do_dataflow, DataflowResultsCursor, DebugFormatted};
54-
use crate::dataflow::{DataflowResults, DataflowResultsConsumer, FlowAtLocation};
52+
use crate::dataflow::generic::{self as dataflow, Analysis};
5553
use crate::dataflow::{MaybeBorrowedLocals, MaybeStorageLive, RequiresStorage};
5654
use crate::transform::no_landing_pads::no_landing_pads;
5755
use crate::transform::simplify;
@@ -467,7 +465,6 @@ fn locals_live_across_suspend_points(
467465
source: MirSource<'tcx>,
468466
movable: bool,
469467
) -> LivenessInfo {
470-
let dead_unwinds = BitSet::new_empty(body.basic_blocks().len());
471468
let def_id = source.def_id();
472469
let body_ref: &Body<'_> = &body;
473470

@@ -488,22 +485,16 @@ fn locals_live_across_suspend_points(
488485
let borrowed_locals_results =
489486
MaybeBorrowedLocals::all_borrows().into_engine(tcx, body_ref, def_id).iterate_to_fixpoint();
490487

491-
let mut borrowed_locals_cursor = ResultsCursor::new(body_ref, &borrowed_locals_results);
488+
let mut borrowed_locals_cursor =
489+
dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
492490

493491
// Calculate the MIR locals that we actually need to keep storage around
494492
// for.
495-
let requires_storage_analysis = RequiresStorage::new(body, &borrowed_locals_results);
496-
let requires_storage_results = do_dataflow(
497-
tcx,
498-
body_ref,
499-
def_id,
500-
&[],
501-
&dead_unwinds,
502-
requires_storage_analysis,
503-
|bd, p| DebugFormatted::new(&bd.body().local_decls[p]),
504-
);
493+
let requires_storage_results = RequiresStorage::new(body, &borrowed_locals_results)
494+
.into_engine(tcx, body_ref, def_id)
495+
.iterate_to_fixpoint();
505496
let mut requires_storage_cursor =
506-
DataflowResultsCursor::new(&requires_storage_results, body_ref);
497+
dataflow::ResultsCursor::new(body_ref, &requires_storage_results);
507498

508499
// Calculate the liveness of MIR locals ignoring borrows.
509500
let mut live_locals = liveness::LiveVarSet::new_empty(body.local_decls.len());
@@ -539,7 +530,7 @@ fn locals_live_across_suspend_points(
539530
// after a suspension point
540531
storage_liveness_map.insert(block, storage_liveness.clone());
541532

542-
requires_storage_cursor.seek(loc);
533+
requires_storage_cursor.seek_before(loc);
543534
let storage_required = requires_storage_cursor.get().clone();
544535

545536
// Locals live are live at this point only if they are used across
@@ -609,7 +600,7 @@ fn compute_storage_conflicts(
609600
body: &'mir Body<'tcx>,
610601
stored_locals: &liveness::LiveVarSet,
611602
ignored: &StorageIgnored,
612-
requires_storage: DataflowResults<'tcx, RequiresStorage<'mir, 'tcx>>,
603+
requires_storage: dataflow::Results<'tcx, RequiresStorage<'mir, 'tcx>>,
613604
) -> BitMatrix<GeneratorSavedLocal, GeneratorSavedLocal> {
614605
assert_eq!(body.local_decls.len(), ignored.0.domain_size());
615606
assert_eq!(body.local_decls.len(), stored_locals.domain_size());
@@ -627,8 +618,10 @@ fn compute_storage_conflicts(
627618
stored_locals: &stored_locals,
628619
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
629620
};
630-
let mut state = FlowAtLocation::new(requires_storage);
631-
visitor.analyze_results(&mut state);
621+
622+
// FIXME: Do we need to do this in RPO?
623+
requires_storage.visit_in_rpo_with(body, &mut visitor);
624+
632625
let local_conflicts = visitor.local_conflicts;
633626

634627
// Compress the matrix using only stored locals (Local -> GeneratorSavedLocal).
@@ -657,60 +650,45 @@ fn compute_storage_conflicts(
657650
storage_conflicts
658651
}
659652

660-
struct StorageConflictVisitor<'body, 'tcx, 's> {
661-
body: &'body Body<'tcx>,
653+
struct StorageConflictVisitor<'mir, 'tcx, 's> {
654+
body: &'mir Body<'tcx>,
662655
stored_locals: &'s liveness::LiveVarSet,
663656
// FIXME(tmandry): Consider using sparse bitsets here once we have good
664657
// benchmarks for generators.
665658
local_conflicts: BitMatrix<Local, Local>,
666659
}
667660

668-
impl<'body, 'tcx, 's> DataflowResultsConsumer<'body, 'tcx>
669-
for StorageConflictVisitor<'body, 'tcx, 's>
670-
{
671-
type FlowState = FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>;
672-
673-
fn body(&self) -> &'body Body<'tcx> {
674-
self.body
675-
}
676-
677-
fn visit_block_entry(&mut self, block: BasicBlock, flow_state: &Self::FlowState) {
678-
// statement_index is only used for logging, so this is fine.
679-
self.apply_state(flow_state, Location { block, statement_index: 0 });
680-
}
661+
impl dataflow::ResultsVisitor<'mir, 'tcx> for StorageConflictVisitor<'mir, 'tcx, '_> {
662+
type FlowState = BitSet<Local>;
681663

682-
fn visit_statement_entry(
664+
fn visit_statement(
683665
&mut self,
666+
state: &Self::FlowState,
667+
_statement: &'mir Statement<'tcx>,
684668
loc: Location,
685-
_stmt: &Statement<'tcx>,
686-
flow_state: &Self::FlowState,
687669
) {
688-
self.apply_state(flow_state, loc);
670+
self.apply_state(state, loc);
689671
}
690672

691-
fn visit_terminator_entry(
673+
fn visit_terminator(
692674
&mut self,
675+
state: &Self::FlowState,
676+
_terminator: &'mir Terminator<'tcx>,
693677
loc: Location,
694-
_term: &Terminator<'tcx>,
695-
flow_state: &Self::FlowState,
696678
) {
697-
self.apply_state(flow_state, loc);
679+
self.apply_state(state, loc);
698680
}
699681
}
700682

701683
impl<'body, 'tcx, 's> StorageConflictVisitor<'body, 'tcx, 's> {
702-
fn apply_state(
703-
&mut self,
704-
flow_state: &FlowAtLocation<'tcx, RequiresStorage<'body, 'tcx>>,
705-
loc: Location,
706-
) {
684+
fn apply_state(&mut self, flow_state: &BitSet<Local>, loc: Location) {
707685
// Ignore unreachable blocks.
708686
match self.body.basic_blocks()[loc.block].terminator().kind {
709687
TerminatorKind::Unreachable => return,
710688
_ => (),
711689
};
712690

713-
let mut eligible_storage_live = flow_state.as_dense().clone();
691+
let mut eligible_storage_live = flow_state.clone();
714692
eligible_storage_live.intersect(&self.stored_locals);
715693

716694
for local in eligible_storage_live.iter() {

0 commit comments

Comments
 (0)