2020//! dominates all loop blocks by definition).
2121
2222use super :: utils:: {
23- build_predecessors, for_each_use, instr_dest, rewrite_terminator_target, terminator_successors,
23+ build_predecessors, compute_idoms, for_each_use, instr_dest, rewrite_terminator_target,
24+ terminator_successors,
2425} ;
2526use crate :: ir:: { BlockId , IrBlock , IrFunction , IrInstr , IrTerminator , VarId } ;
2627use std:: collections:: { HashMap , HashSet } ;
@@ -32,8 +33,8 @@ pub fn eliminate(func: &mut IrFunction) {
3233 }
3334
3435 let preds = build_predecessors ( func) ;
35- let dominators = compute_dominators ( func, & preds ) ;
36- let back_edges = find_back_edges ( func, & dominators ) ;
36+ let idom = compute_idoms ( func) ;
37+ let back_edges = find_back_edges ( func, & idom ) ;
3738
3839 if back_edges. is_empty ( ) {
3940 return ;
@@ -46,81 +47,33 @@ pub fn eliminate(func: &mut IrFunction) {
4647 }
4748}
4849
49- // ── Dominator computation ────────────────────────────────────────────────────
50-
51- /// Compute the dominator set for each block using the iterative algorithm.
52- ///
53- /// Returns a map from each block to the set of blocks that dominate it.
54- fn compute_dominators (
55- func : & IrFunction ,
56- preds : & HashMap < BlockId , HashSet < BlockId > > ,
57- ) -> HashMap < BlockId , HashSet < BlockId > > {
58- let entry = func. entry_block ;
59- let all_block_ids: HashSet < BlockId > = func. blocks . iter ( ) . map ( |b| b. id ) . collect ( ) ;
60-
61- let mut dom: HashMap < BlockId , HashSet < BlockId > > = HashMap :: new ( ) ;
62- dom. insert ( entry, HashSet :: from ( [ entry] ) ) ;
63-
64- for block in & func. blocks {
65- if block. id != entry {
66- dom. insert ( block. id , all_block_ids. clone ( ) ) ;
67- }
68- }
50+ // ── Back edge detection ──────────────────────────────────────────────────────
6951
52+ /// Returns `true` if `d` dominates `b` according to the idom tree.
53+ fn dominates ( d : BlockId , b : BlockId , idom : & HashMap < BlockId , BlockId > ) -> bool {
54+ let mut cur = b;
7055 loop {
71- let mut changed = false ;
72- for block in & func. blocks {
73- if block. id == entry {
74- continue ;
75- }
76- let pred_set = & preds[ & block. id ] ;
77- if pred_set. is_empty ( ) {
78- continue ;
79- }
80-
81- // new_dom = {self} ∪ ∩(dom[p] for p in preds)
82- let mut new_dom: Option < HashSet < BlockId > > = None ;
83- for p in pred_set {
84- if let Some ( p_dom) = dom. get ( p) {
85- new_dom = Some ( match new_dom {
86- None => p_dom. clone ( ) ,
87- Some ( current) => current. intersection ( p_dom) . copied ( ) . collect ( ) ,
88- } ) ;
89- }
90- }
91-
92- let mut new_dom = new_dom. unwrap_or_default ( ) ;
93- new_dom. insert ( block. id ) ;
94-
95- if new_dom != dom[ & block. id ] {
96- dom. insert ( block. id , new_dom) ;
97- changed = true ;
98- }
56+ if cur == d {
57+ return true ;
9958 }
100- if !changed {
101- break ;
59+ match idom. get ( & cur) {
60+ Some ( & parent) if parent != cur => cur = parent,
61+ _ => return false ,
10262 }
10363 }
104-
105- dom
10664}
10765
108- // ── Back edge detection ──────────────────────────────────────────────────────
109-
11066/// Find all back edges in the CFG.
11167///
11268/// A back edge is (src, tgt) where tgt dominates src.
11369fn find_back_edges (
11470 func : & IrFunction ,
115- dominators : & HashMap < BlockId , HashSet < BlockId > > ,
71+ idom : & HashMap < BlockId , BlockId > ,
11672) -> Vec < ( BlockId , BlockId ) > {
11773 let mut back_edges = Vec :: new ( ) ;
11874 for block in & func. blocks {
11975 for succ in terminator_successors ( & block. terminator ) {
120- if dominators
121- . get ( & block. id )
122- . is_some_and ( |dom_set| dom_set. contains ( & succ) )
123- {
76+ if dominates ( succ, block. id , idom) {
12477 back_edges. push ( ( block. id , succ) ) ;
12578 }
12679 }
@@ -1186,15 +1139,11 @@ mod tests {
11861139 } ,
11871140 ] ) ;
11881141
1189- let preds = build_predecessors ( & func) ;
1190- let dom = compute_dominators ( & func, & preds) ;
1142+ let idom = compute_idoms ( & func) ;
11911143
1192- assert_eq ! ( dom[ & BlockId ( 0 ) ] , HashSet :: from( [ BlockId ( 0 ) ] ) ) ;
1193- assert_eq ! ( dom[ & BlockId ( 1 ) ] , HashSet :: from( [ BlockId ( 0 ) , BlockId ( 1 ) ] ) ) ;
1194- assert_eq ! (
1195- dom[ & BlockId ( 2 ) ] ,
1196- HashSet :: from( [ BlockId ( 0 ) , BlockId ( 1 ) , BlockId ( 2 ) ] )
1197- ) ;
1144+ assert_eq ! ( idom[ & BlockId ( 0 ) ] , BlockId ( 0 ) ) ; // entry is its own idom
1145+ assert_eq ! ( idom[ & BlockId ( 1 ) ] , BlockId ( 0 ) ) ;
1146+ assert_eq ! ( idom[ & BlockId ( 2 ) ] , BlockId ( 1 ) ) ;
11981147 }
11991148
12001149 #[ test]
@@ -1227,11 +1176,12 @@ mod tests {
12271176 } ,
12281177 ] ) ;
12291178
1230- let preds = build_predecessors ( & func) ;
1231- let dom = compute_dominators ( & func, & preds) ;
1179+ let idom = compute_idoms ( & func) ;
12321180
1233- // B3 is dominated by B0 (only common dominator of B1 and B2).
1234- assert_eq ! ( dom[ & BlockId ( 3 ) ] , HashSet :: from( [ BlockId ( 0 ) , BlockId ( 3 ) ] ) ) ;
1181+ // B3's idom is B0 — the only block that dominates both B1 and B2.
1182+ assert_eq ! ( idom[ & BlockId ( 3 ) ] , BlockId ( 0 ) ) ;
1183+ assert_eq ! ( idom[ & BlockId ( 1 ) ] , BlockId ( 0 ) ) ;
1184+ assert_eq ! ( idom[ & BlockId ( 2 ) ] , BlockId ( 0 ) ) ;
12351185 }
12361186
12371187 #[ test]
@@ -1255,9 +1205,8 @@ mod tests {
12551205 } ,
12561206 ] ) ;
12571207
1258- let preds = build_predecessors ( & func) ;
1259- let dom = compute_dominators ( & func, & preds) ;
1260- let back_edges = find_back_edges ( & func, & dom) ;
1208+ let idom = compute_idoms ( & func) ;
1209+ let back_edges = find_back_edges ( & func, & idom) ;
12611210
12621211 assert_eq ! ( back_edges. len( ) , 1 ) ;
12631212 assert_eq ! ( back_edges[ 0 ] , ( BlockId ( 2 ) , BlockId ( 1 ) ) ) ;
@@ -1291,8 +1240,8 @@ mod tests {
12911240 ] ) ;
12921241
12931242 let preds = build_predecessors ( & func) ;
1294- let dom = compute_dominators ( & func, & preds ) ;
1295- let back_edges = find_back_edges ( & func, & dom ) ;
1243+ let idom = compute_idoms ( & func) ;
1244+ let back_edges = find_back_edges ( & func, & idom ) ;
12961245 let loops = find_natural_loops ( & back_edges, & preds) ;
12971246
12981247 assert_eq ! ( loops. len( ) , 1 ) ;
0 commit comments