Skip to content

Commit 3e0b7e5

Browse files
authored
loop analysis simplification (#9613)
* loop analysis simplification * add iterator over reverse post order * review comments * review comments * use rpo iterator where possible * make use of same struct access pattern throughout * use new directly instead of calling macro
1 parent d3132c9 commit 3e0b7e5

File tree

4 files changed

+46
-35
lines changed

4 files changed

+46
-35
lines changed

cranelift/codegen/src/dominator_tree.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ impl DominatorTree {
6060
&self.postorder
6161
}
6262

63+
/// Get an iterator over CFG reverse post-order of blocks used to compute the dominator tree.
64+
///
65+
/// Note that the post-order is not updated automatically when the CFG is modified. It is
66+
/// computed from scratch and cached by `compute()`.
67+
pub fn cfg_rpo(&self) -> impl Iterator<Item = &Block> {
68+
debug_assert!(self.is_valid());
69+
self.postorder.iter().rev()
70+
}
71+
6372
/// Returns the immediate dominator of `block`.
6473
///
6574
/// `block_a` is said to *dominate* `block_b` if all control flow paths from the function

cranelift/codegen/src/loop_analysis.rs

Lines changed: 33 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use crate::dominator_tree::DominatorTree;
55
use crate::entity::entity_impl;
66
use crate::entity::SecondaryMap;
77
use crate::entity::{Keys, PrimaryMap};
8-
use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
8+
use crate::flowgraph::ControlFlowGraph;
99
use crate::ir::{Block, Function, Layout};
1010
use crate::packed_option::PackedOption;
1111
use crate::timing;
1212
use alloc::vec::Vec;
13-
use smallvec::{smallvec, SmallVec};
13+
use smallvec::SmallVec;
1414

1515
/// A opaque reference to a code loop.
1616
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
@@ -190,6 +190,19 @@ impl LoopAnalysis {
190190
self.valid = false;
191191
}
192192

193+
// Determines if a block dominates any predecessor
194+
// and thus is a loop header.
195+
fn is_block_loop_header(
196+
block: Block,
197+
cfg: &ControlFlowGraph,
198+
domtree: &DominatorTree,
199+
layout: &Layout,
200+
) -> bool {
201+
// A block is a loop header if it dominates any of its predecessors.
202+
cfg.pred_iter(block)
203+
.any(|pred| domtree.dominates(block, pred.inst, layout))
204+
}
205+
193206
// Traverses the CFG in reverse postorder and create a loop object for every block having a
194207
// back edge.
195208
fn find_loop_headers(
@@ -198,21 +211,13 @@ impl LoopAnalysis {
198211
domtree: &DominatorTree,
199212
layout: &Layout,
200213
) {
201-
// We traverse the CFG in reverse postorder
202-
for &block in domtree.cfg_postorder().iter().rev() {
203-
for BlockPredecessor {
204-
inst: pred_inst, ..
205-
} in cfg.pred_iter(block)
206-
{
207-
// If the block dominates one of its predecessors it is a back edge
208-
if domtree.dominates(block, pred_inst, layout) {
209-
// This block is a loop header, so we create its associated loop
210-
let lp = self.loops.push(LoopData::new(block, None));
211-
self.block_loop_map[block] = lp.into();
212-
break;
213-
// We break because we only need one back edge to identify a loop header.
214-
}
215-
}
214+
for &block in domtree
215+
.cfg_rpo()
216+
.filter(|&&block| Self::is_block_loop_header(block, cfg, domtree, layout))
217+
{
218+
// This block is a loop header, so we create its associated loop
219+
let lp = self.loops.push(LoopData::new(block, None));
220+
self.block_loop_map[block] = lp.into();
216221
}
217222
}
218223

@@ -229,16 +234,15 @@ impl LoopAnalysis {
229234
// We handle each loop header in reverse order, corresponding to a pseudo postorder
230235
// traversal of the graph.
231236
for lp in self.loops().rev() {
232-
for BlockPredecessor {
233-
block: pred,
234-
inst: pred_inst,
235-
} in cfg.pred_iter(self.loops[lp].header)
236-
{
237-
// We follow the back edges
238-
if domtree.dominates(self.loops[lp].header, pred_inst, layout) {
239-
stack.push(pred);
240-
}
241-
}
237+
// Push all predecessors of this header that it dominates onto the stack.
238+
stack.extend(
239+
cfg.pred_iter(self.loops[lp].header)
240+
.filter(|pred| {
241+
// We follow the back edges
242+
domtree.dominates(self.loops[lp].header, pred.inst, layout)
243+
})
244+
.map(|pred| pred.block),
245+
);
242246
while let Some(node) = stack.pop() {
243247
let continue_dfs: Option<Block>;
244248
match self.block_loop_map[node].expand() {
@@ -283,16 +287,14 @@ impl LoopAnalysis {
283287
// Now we have handled the popped node and need to continue the DFS by adding the
284288
// predecessors of that node
285289
if let Some(continue_dfs) = continue_dfs {
286-
for BlockPredecessor { block: pred, .. } in cfg.pred_iter(continue_dfs) {
287-
stack.push(pred)
288-
}
290+
stack.extend(cfg.pred_iter(continue_dfs).map(|pred| pred.block));
289291
}
290292
}
291293
}
292294
}
293295

294296
fn assign_loop_levels(&mut self) {
295-
let mut stack: SmallVec<[Loop; 8]> = smallvec![];
297+
let mut stack: SmallVec<[Loop; 8]> = SmallVec::new();
296298
for lp in self.loops.keys() {
297299
if self.loops[lp].level == LoopLevel::invalid() {
298300
stack.push(lp);

cranelift/codegen/src/machinst/blockorder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ impl BlockLoweringOrder {
192192

193193
let mut lowered_order = Vec::new();
194194

195-
for &block in domtree.cfg_postorder().iter().rev() {
195+
for &block in domtree.cfg_rpo() {
196196
lowered_order.push(LoweredBlock::Orig { block });
197197

198198
if block_out_count[block] > 1 {

cranelift/codegen/src/remove_constant_phis.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
233233
let mut summaries =
234234
SecondaryMap::<Block, BlockSummary>::with_capacity(domtree.cfg_postorder().len());
235235

236-
for b in domtree.cfg_postorder().iter().rev().copied() {
236+
for b in domtree.cfg_rpo().copied() {
237237
let formals = func.dfg.block_params(b);
238238
let mut summary = BlockSummary::new(&bump, formals);
239239

@@ -269,7 +269,7 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
269269
// Set up initial solver state
270270
let mut state = SolverState::new();
271271

272-
for b in domtree.cfg_postorder().iter().rev().copied() {
272+
for b in domtree.cfg_rpo().copied() {
273273
// For each block, get the formals
274274
if b == entry_block {
275275
continue;
@@ -288,7 +288,7 @@ pub fn do_remove_constant_phis(func: &mut Function, domtree: &mut DominatorTree)
288288
iter_no += 1;
289289
let mut changed = false;
290290

291-
for src in domtree.cfg_postorder().iter().rev().copied() {
291+
for src in domtree.cfg_rpo().copied() {
292292
let src_summary = &summaries[src];
293293
for edge in &src_summary.dests {
294294
assert!(edge.block != entry_block);

0 commit comments

Comments
 (0)