Skip to content

Commit 10b7eec

Browse files
authored
Rollup merge of #74169 - ecstatic-morse:dataflow-unreachable, r=pnkfelix
Stop processing unreachable blocks when solving dataflow ...instead we `debug_assert` that the user is not checking the dataflow state for an unreachable block. This resolves a FIXME in the dataflow engine. The old behavior was an artifact of the previous dataflow framework. Things should run a tiny bit faster now, but I suspect not enough to show up in benchmarks. AFAIK, only the generator transform runs dataflow on MIR with unreachable basic blocks. This PR also adds some utility methods to `mir::traversal`. r? @pnkfelix
2 parents 9c84c6b + 698e870 commit 10b7eec

File tree

5 files changed

+42
-12
lines changed

5 files changed

+42
-12
lines changed

Diff for: src/librustc_middle/mir/traversal.rs

+17
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,20 @@ impl<'a, 'tcx> Iterator for ReversePostorder<'a, 'tcx> {
292292
}
293293

294294
impl<'a, 'tcx> ExactSizeIterator for ReversePostorder<'a, 'tcx> {}
295+
296+
/// Returns an iterator over all basic blocks reachable from the `START_BLOCK` in no particular
297+
/// order.
298+
///
299+
/// This is clearer than writing `preorder` in cases where the order doesn't matter.
300+
pub fn reachable<'a, 'tcx>(
301+
body: &'a Body<'tcx>,
302+
) -> impl 'a + Iterator<Item = (BasicBlock, &'a BasicBlockData<'tcx>)> {
303+
preorder(body)
304+
}
305+
306+
/// Returns a `BitSet` containing all basic blocks reachable from the `START_BLOCK`.
307+
pub fn reachable_as_bitset(body: &Body<'tcx>) -> BitSet<BasicBlock> {
308+
let mut iter = preorder(body);
309+
(&mut iter).for_each(drop);
310+
iter.visited
311+
}

Diff for: src/librustc_mir/dataflow/framework/cursor.rs

+9
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ where
3434
///
3535
/// When this flag is set, we need to reset to an entry set before doing a seek.
3636
state_needs_reset: bool,
37+
38+
#[cfg(debug_assertions)]
39+
reachable_blocks: BitSet<BasicBlock>,
3740
}
3841

3942
impl<'mir, 'tcx, A, R> ResultsCursor<'mir, 'tcx, A, R>
@@ -55,6 +58,9 @@ where
5558
state_needs_reset: true,
5659
state: BitSet::new_empty(bits_per_block),
5760
pos: CursorPosition::block_entry(mir::START_BLOCK),
61+
62+
#[cfg(debug_assertions)]
63+
reachable_blocks: mir::traversal::reachable_as_bitset(body),
5864
}
5965
}
6066

@@ -85,6 +91,9 @@ where
8591
///
8692
/// For backward dataflow analyses, this is the dataflow state after the terminator.
8793
pub(super) fn seek_to_block_entry(&mut self, block: BasicBlock) {
94+
#[cfg(debug_assertions)]
95+
assert!(self.reachable_blocks.contains(block));
96+
8897
self.state.overwrite(&self.results.borrow().entry_set_for_block(block));
8998
self.pos = CursorPosition::block_entry(block);
9099
self.state_needs_reset = false;

Diff for: src/librustc_mir/dataflow/framework/engine.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ where
5252
visit_results(body, blocks, self, vis)
5353
}
5454

55+
pub fn visit_reachable_with(
56+
&self,
57+
body: &'mir mir::Body<'tcx>,
58+
vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet<A::Idx>>,
59+
) {
60+
let blocks = mir::traversal::reachable(body);
61+
visit_results(body, blocks.map(|(bb, _)| bb), self, vis)
62+
}
63+
5564
pub fn visit_in_rpo_with(
5665
&self,
5766
body: &'mir mir::Body<'tcx>,
@@ -204,15 +213,6 @@ where
204213
}
205214
}
206215

207-
// Add blocks that are not reachable from START_BLOCK to the work queue. These blocks will
208-
// be processed after the ones added above.
209-
//
210-
// FIXME(ecstaticmorse): Is this actually necessary? In principle, we shouldn't need to
211-
// know the dataflow state in unreachable basic blocks.
212-
for bb in body.basic_blocks().indices() {
213-
dirty_queue.insert(bb);
214-
}
215-
216216
let mut state = BitSet::new_empty(bits_per_block);
217217
while let Some(bb) = dirty_queue.pop() {
218218
let bb_data = &body[bb];

Diff for: src/librustc_mir/dataflow/framework/visitor.rs

+6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ pub fn visit_results<F, V>(
1616
{
1717
let mut state = results.new_flow_state(body);
1818

19+
#[cfg(debug_assertions)]
20+
let reachable_blocks = mir::traversal::reachable_as_bitset(body);
21+
1922
for block in blocks {
23+
#[cfg(debug_assertions)]
24+
assert!(reachable_blocks.contains(block));
25+
2026
let block_data = &body[block];
2127
V::Direction::visit_results_in_block(&mut state, block, block_data, results, vis);
2228
}

Diff for: src/librustc_mir/transform/generator.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -624,9 +624,7 @@ fn compute_storage_conflicts(
624624
local_conflicts: BitMatrix::from_row_n(&ineligible_locals, body.local_decls.len()),
625625
};
626626

627-
// Visit only reachable basic blocks. The exact order is not important.
628-
let reachable_blocks = traversal::preorder(body).map(|(bb, _)| bb);
629-
requires_storage.visit_with(body, reachable_blocks, &mut visitor);
627+
requires_storage.visit_reachable_with(body, &mut visitor);
630628

631629
let local_conflicts = visitor.local_conflicts;
632630

0 commit comments

Comments
 (0)