| use rustc_index::bit_set::DenseBitSet; |
| |
| use super::*; |
| |
| /// Compute the set of loop headers in the given body. A loop header is usually defined as a block |
| /// which dominates one of its predecessors. This definition is only correct for reducible CFGs. |
| /// However, computing dominators is expensive, so we approximate according to the post-order |
| /// traversal order. A loop header for us is a block which is visited after its predecessor in |
| /// post-order. This is ok as we mostly need a heuristic. |
| pub fn maybe_loop_headers(body: &Body<'_>) -> DenseBitSet<BasicBlock> { |
| let mut maybe_loop_headers = DenseBitSet::new_empty(body.basic_blocks.len()); |
| let mut visited = DenseBitSet::new_empty(body.basic_blocks.len()); |
| for (bb, bbdata) in traversal::postorder(body) { |
| // Post-order means we visit successors before the block for acyclic CFGs. |
| // If the successor is not visited yet, consider it a loop header. |
| for succ in bbdata.terminator().successors() { |
| if !visited.contains(succ) { |
| maybe_loop_headers.insert(succ); |
| } |
| } |
| |
| // Only mark `bb` as visited after we checked the successors, in case we have a self-loop. |
| // bb1: goto -> bb1; |
| let _new = visited.insert(bb); |
| debug_assert!(_new); |
| } |
| |
| maybe_loop_headers |
| } |