Skip to content

Commit 9622cb5

Browse files
author
metrics
committed
refactor: replace dominator computation with immediate dominator tree in LICM
1 parent 9c7b113 commit 9622cb5

1 file changed

Lines changed: 28 additions & 79 deletions

File tree

  • crates/herkos-core/src/optimizer

crates/herkos-core/src/optimizer/licm.rs

Lines changed: 28 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
//! dominates all loop blocks by definition).
2121
2222
use 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
};
2526
use crate::ir::{BlockId, IrBlock, IrFunction, IrInstr, IrTerminator, VarId};
2627
use 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.
11369
fn 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

Comments
 (0)