Skip to content

Commit 543c464

Browse files
authored
Rollup merge of #62062 - ecstatic-morse:dataflow-order, r=nagisa
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 (see [this blog post](https://eli.thegreenplace.net/2015/directed-graph-traversal-orderings-and-applications-to-data-flow-analysis/#data-flow-analysis) for more info). 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 may be pretty close to RPO already--`BasicBlock(0)` is already the start block--in which case the cost of doing the traversal up front will outweigh the efficiency gains. A perf run is needed to check this. r? @pnkfelix (I think).
2 parents 0af8e87 + 07c5e2b commit 543c464

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

Lines changed: 18 additions & 2 deletions
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)