Skip to content

Commit 07c5e2b

Browse files
Use a more efficient iteration order for forward dataflow
Currently, dataflow begins by visiting each block in order of ID (`BasicBlock(0)`, `BasicBlock(1)`, etc.). This PR changes that initial iteration to reverse post-order. This ensures that the effects of all predecessors will be applied before a basic block is visited if the CFG has no back-edges, and should result in less total iterations even when back-edges exist. This should not change the results of dataflow analysis. The current ordering for basic blocks is pretty close to RPO already--`BasicBlock(0)` is already the start block, so the gains from this are pretty small, especially since we need to do an extra traversal up front. Note that some basic blocks are unreachable from the `START_BLOCK` during dataflow. We add these blocks to the work queue as well to preserve the original behavior.
1 parent a5b1729 commit 07c5e2b

File tree

1 file changed

+18
-2
lines changed
  • src/librustc_mir/dataflow

1 file changed

+18
-2
lines changed

src/librustc_mir/dataflow/mod.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -228,9 +228,25 @@ where
228228
BD: BitDenotation<'tcx>,
229229
{
230230
fn walk_cfg(&mut self, in_out: &mut BitSet<BD::Idx>) {
231-
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
232-
WorkQueue::with_all(self.builder.body.basic_blocks().len());
233231
let body = self.builder.body;
232+
233+
// Initialize the dirty queue in reverse post-order. This makes it more likely that the
234+
// entry state for each basic block will have the effects of its predecessors applied
235+
// before it is processed. In fact, for CFGs without back edges, this guarantees that
236+
// dataflow will converge in exactly `N` iterations, where `N` is the number of basic
237+
// blocks.
238+
let mut dirty_queue: WorkQueue<mir::BasicBlock> =
239+
WorkQueue::with_none(body.basic_blocks().len());
240+
for (bb, _) in traversal::reverse_postorder(body) {
241+
dirty_queue.insert(bb);
242+
}
243+
244+
// Add blocks which are not reachable from START_BLOCK to the work queue. These blocks will
245+
// be processed after the ones added above.
246+
for bb in body.basic_blocks().indices() {
247+
dirty_queue.insert(bb);
248+
}
249+
234250
while let Some(bb) = dirty_queue.pop() {
235251
let (on_entry, trans) = self.builder.flow_state.sets.get_mut(bb.index());
236252
debug_assert!(in_out.words().len() == on_entry.words().len());

0 commit comments

Comments
 (0)