1use std::cell::OnceCell;
13use std::collections::{HashMap, HashSet};
14use std::hash::{BuildHasher, Hash};
15
16use crate::graph::{Cfg, FxBuildHasher};
17
18pub fn reachable_from_root<C: Cfg>(graph: &C, root: C::NodeId) -> Vec<C::NodeId> {
19 let mut visited: HashSet<C::NodeId, C::Hasher> = HashSet::default();
20 let mut order = Vec::new();
21 let mut stack = vec![root];
22 while let Some(node) = stack.pop() {
23 if !visited.insert(node) {
24 continue;
25 }
26 order.push(node);
27 for succ in graph.successors(node) {
28 if !visited.contains(&succ) {
29 stack.push(succ);
30 }
31 }
32 }
33 order
34}
35
36pub struct DominatorTree<N: Copy + Hash + Eq, S: BuildHasher + Default = FxBuildHasher> {
53 root: N,
54 idom: HashMap<N, N, S>,
55 preds: HashMap<N, Vec<N>, S>,
56 dominator_sets: OnceCell<HashMap<N, HashSet<N, S>, S>>,
57 children: OnceCell<HashMap<N, Vec<N>, S>>,
58 frontier: OnceCell<HashMap<N, HashSet<N, S>, S>>,
59}
60
61impl<N: Copy + Hash + Eq, S: BuildHasher + Default> DominatorTree<N, S> {
62 pub fn root(&self) -> N {
64 self.root
65 }
66
67 pub fn immediate_dominator(&self, node: N) -> Option<N> {
70 self.idom.get(&node).copied()
71 }
72
73 pub fn children_of(&self, node: N) -> &[N] {
76 self.children_map()
77 .get(&node)
78 .map(Vec::as_slice)
79 .unwrap_or(&[])
80 }
81
82 pub fn dominates(&self, dominator: N, node: N) -> bool {
87 self.dominator_sets_map()
88 .get(&node)
89 .is_some_and(|s| s.contains(&dominator))
90 }
91
92 pub fn dominator_set(&self, node: N) -> Option<&HashSet<N, S>> {
97 self.dominator_sets_map().get(&node)
98 }
99
100 fn children_map(&self) -> &HashMap<N, Vec<N>, S> {
101 self.children.get_or_init(|| {
102 let mut map: HashMap<N, Vec<N>, S> = HashMap::default();
103 for (&n, &parent) in &self.idom {
104 map.entry(parent).or_default().push(n);
105 }
106 map
107 })
108 }
109
110 pub fn dominator_frontier(&self) -> &HashMap<N, HashSet<N, S>, S> {
118 self.frontier.get_or_init(|| {
119 let mut all_nodes: HashSet<N, S> = self.idom.keys().copied().collect();
120 all_nodes.insert(self.root);
121
122 let mut frontier: HashMap<N, HashSet<N, S>, S> =
123 all_nodes.iter().map(|&n| (n, HashSet::default())).collect();
124
125 for (&n, preds) in &self.preds {
126 let idom_n = match self.idom.get(&n) {
127 Some(&d) => d,
128 None => continue,
129 };
130
131 if preds.len() < 2 {
132 continue;
133 }
134
135 for &p in preds {
136 let mut runner = p;
137 while runner != idom_n {
138 frontier.entry(runner).or_default().insert(n);
139 match self.idom.get(&runner) {
140 Some(&parent) => runner = parent,
141 None => break,
142 }
143 }
144 }
145 }
146
147 frontier
148 })
149 }
150
151 fn dominator_sets_map(&self) -> &HashMap<N, HashSet<N, S>, S> {
152 self.dominator_sets
153 .get_or_init(|| compute_dominator_sets(&self.idom, self.root))
154 }
155}
156
157pub fn compute_dominators<C: Cfg>(
168 graph: &C,
169 root: C::NodeId,
170) -> DominatorTree<C::NodeId, C::Hasher> {
171 let nodes = reachable_from_root(graph, root);
172 let node_set: HashSet<C::NodeId, C::Hasher> = nodes.iter().copied().collect();
173
174 let result = run_lengauer_tarjan(graph, &node_set, root);
175
176 DominatorTree {
177 root,
178 idom: result.idom,
179 preds: result.preds,
180 dominator_sets: OnceCell::new(),
181 children: OnceCell::new(),
182 frontier: OnceCell::new(),
183 }
184}
185
186fn compute_dominator_sets<N: Copy + Hash + Eq, S: BuildHasher + Default>(
195 idom: &HashMap<N, N, S>,
196 root: N,
197) -> HashMap<N, HashSet<N, S>, S> {
198 let mut all_nodes: HashSet<N, S> = idom.keys().copied().collect();
199 all_nodes.insert(root);
200
201 let mut out = HashMap::default();
202 for n in all_nodes {
203 let mut set = HashSet::default();
204 let mut cursor = n;
205 loop {
206 set.insert(cursor);
207 match idom.get(&cursor) {
208 Some(&parent) => cursor = parent,
209 None => break,
210 }
211 }
212 out.insert(n, set);
213 }
214 out
215}
216
217struct TarjanResult<C: Cfg> {
218 idom: HashMap<C::NodeId, C::NodeId, C::Hasher>,
219 preds: HashMap<C::NodeId, Vec<C::NodeId>, C::Hasher>,
220}
221
222impl<C: Cfg> Default for TarjanResult<C> {
223 fn default() -> Self {
224 Self {
225 idom: HashMap::default(),
226 preds: HashMap::default(),
227 }
228 }
229}
230
231fn run_lengauer_tarjan<C: Cfg>(
234 graph: &C,
235 node_set: &HashSet<C::NodeId, C::Hasher>,
236 root: C::NodeId,
237) -> TarjanResult<C> {
238 let mut state = LtState::new(graph, node_set);
239 state.dfs(root, 0);
240
241 let n = state.last_index();
242 if n == 0 {
243 return TarjanResult::default();
244 }
245
246 for w in (2..=n).rev() {
247 let preds = state.pred[w].clone();
248 for v in preds {
249 let u = state.eval(v);
250 if state.semi[u] < state.semi[w] {
251 state.semi[w] = state.semi[u];
252 }
253 }
254
255 let semi_w = state.semi[w];
256 state.bucket[semi_w].push(w);
257
258 let p = state.parent[w];
259 state.link(p, w);
260
261 let bucket_parent = std::mem::take(&mut state.bucket[p]);
262 for v in bucket_parent {
263 let u = state.eval(v);
264 if state.semi[u] < state.semi[v] {
265 state.idom[v] = u;
266 } else {
267 state.idom[v] = p;
268 }
269 }
270 }
271
272 for w in 2..=n {
273 if state.idom[w] != state.semi[w] {
274 state.idom[w] = state.idom[state.idom[w]];
275 }
276 }
277
278 let mut result = TarjanResult::default();
280
281 let root_node = state.vertex[1].expect("root must have DFS index 1");
282 result.preds.entry(root_node).or_default();
283
284 for w in 2..=n {
285 let node = state.vertex[w].expect("DFS index must map to a node");
286 let idom_idx = state.idom[w];
287 let idom_node = state.vertex[idom_idx].expect("idom index must map to a node");
288 result.idom.insert(node, idom_node);
289
290 let pred_nodes: Vec<C::NodeId> = state.pred[w]
291 .iter()
292 .map(|&idx| state.vertex[idx].expect("pred index must map to a node"))
293 .collect();
294 result.preds.insert(node, pred_nodes);
295 }
296
297 result
298}
299
300struct LtState<'graph, C: Cfg> {
305 graph: &'graph C,
306 node_set: &'graph HashSet<C::NodeId, C::Hasher>,
307
308 number: HashMap<C::NodeId, usize, C::Hasher>,
309 vertex: Vec<Option<C::NodeId>>, parent: Vec<usize>,
311 semi: Vec<usize>,
312 idom: Vec<usize>,
313 ancestor: Vec<usize>,
314 label: Vec<usize>,
315 bucket: Vec<Vec<usize>>,
316 pred: Vec<Vec<usize>>,
317}
318
319impl<'graph, C: Cfg> LtState<'graph, C> {
320 fn new(graph: &'graph C, node_set: &'graph HashSet<C::NodeId, C::Hasher>) -> Self {
321 Self {
322 graph,
323 node_set,
324 number: HashMap::default(),
325 vertex: vec![None],
326 parent: vec![0],
327 semi: vec![0],
328 idom: vec![0],
329 ancestor: vec![0],
330 label: vec![0],
331 bucket: vec![Vec::new()],
332 pred: vec![Vec::new()],
333 }
334 }
335
336 fn last_index(&self) -> usize {
337 self.vertex.len().saturating_sub(1)
338 }
339
340 fn push_vertex(&mut self, node: C::NodeId, parent: usize) -> usize {
341 let idx = self.vertex.len();
342 self.number.insert(node, idx);
343 self.vertex.push(Some(node));
344 self.parent.push(parent);
345 self.semi.push(idx);
346 self.idom.push(0);
347 self.ancestor.push(0);
348 self.label.push(idx);
349 self.bucket.push(Vec::new());
350 self.pred.push(Vec::new());
351 idx
352 }
353
354 fn dfs(&mut self, node: C::NodeId, parent: usize) {
355 if self.number.contains_key(&node) || !self.node_set.contains(&node) {
356 return;
357 }
358
359 let node_idx = self.push_vertex(node, parent);
360
361 let succs: Vec<C::NodeId> = self.graph.successors(node).collect();
362 for succ in succs {
363 if !self.node_set.contains(&succ) {
364 continue;
365 }
366
367 if !self.number.contains_key(&succ) {
368 self.dfs(succ, node_idx);
369 }
370
371 if let Some(&succ_idx) = self.number.get(&succ) {
372 self.pred[succ_idx].push(node_idx);
373 }
374 }
375 }
376
377 fn link(&mut self, parent: usize, child: usize) {
378 self.ancestor[child] = parent;
379 }
380
381 fn compress(&mut self, v: usize) {
382 let a = self.ancestor[v];
383 if a != 0 {
384 let aa = self.ancestor[a];
385 if aa != 0 {
386 self.compress(a);
387
388 if self.semi[self.label[a]] < self.semi[self.label[v]] {
389 self.label[v] = self.label[a];
390 }
391
392 self.ancestor[v] = self.ancestor[a];
393 }
394 }
395 }
396
397 fn eval(&mut self, v: usize) -> usize {
398 if self.ancestor[v] == 0 {
399 return self.label[v];
400 }
401
402 self.compress(v);
403 let a = self.ancestor[v];
404 if a != 0 && self.semi[self.label[a]] < self.semi[self.label[v]] {
405 self.label[v] = self.label[a];
406 }
407
408 self.label[v]
409 }
410}
411
412#[cfg(test)]
417mod tests {
418 use std::collections::HashSet;
419
420 use jstd_derive::Identifier;
421
422 use super::{compute_dominators, reachable_from_root};
423 use crate::graph::owning::OwningGraph;
424
425 #[derive(Identifier)]
426 struct NodeId(usize);
427
428 #[derive(Identifier)]
429 struct EdgeId(usize);
430
431 type TestGraph = OwningGraph<NodeId, EdgeId, (), ()>;
432
433 #[test]
434 fn computes_reachability_from_root() {
435 let mut graph = TestGraph::default();
436
437 let a = graph.make_node(());
438 let b = graph.make_node(());
439 let c = graph.make_node(());
440 let d = graph.make_node(());
441 let x = graph.make_node(());
442
443 graph.make_edge(a, b, ());
444 graph.make_edge(b, c, ());
445 graph.make_edge(c, d, ());
446
447 let reachable: HashSet<_> = reachable_from_root(&graph, a).into_iter().collect();
448
449 assert!(reachable.contains(&a));
450 assert!(reachable.contains(&b));
451 assert!(reachable.contains(&c));
452 assert!(reachable.contains(&d));
453 assert!(!reachable.contains(&x));
454 }
455
456 #[test]
457 fn computes_dominators_on_diamond() {
458 let mut graph = TestGraph::default();
460 let a = graph.make_node(());
461 let b = graph.make_node(());
462 let c = graph.make_node(());
463 let d = graph.make_node(());
464 let e = graph.make_node(());
465 graph.make_edge(a, b, ());
466 graph.make_edge(a, c, ());
467 graph.make_edge(b, d, ());
468 graph.make_edge(c, d, ());
469 graph.make_edge(d, e, ());
470
471 let tree = compute_dominators(&graph, a);
472
473 assert_eq!(tree.dominator_set(a), Some(&HashSet::from_iter([a])));
474 assert!(tree.dominates(a, b) && tree.dominates(b, b));
475 assert!(tree.dominates(a, c) && tree.dominates(c, c));
476 assert!(tree.dominates(a, d));
477 assert!(!tree.dominates(b, d));
478 assert!(!tree.dominates(c, d));
479 assert!(tree.dominates(a, e) && tree.dominates(d, e) && tree.dominates(e, e));
480 }
481
482 #[test]
483 fn immediate_dominator_on_chain() {
484 let mut graph = TestGraph::default();
486 let a = graph.make_node(());
487 let b = graph.make_node(());
488 let c = graph.make_node(());
489 let d = graph.make_node(());
490 graph.make_edge(a, b, ());
491 graph.make_edge(b, c, ());
492 graph.make_edge(c, d, ());
493
494 let tree = compute_dominators(&graph, a);
495
496 assert_eq!(tree.immediate_dominator(b), Some(a));
497 assert_eq!(tree.immediate_dominator(c), Some(b));
498 assert_eq!(tree.immediate_dominator(d), Some(c));
499 assert_eq!(tree.immediate_dominator(a), None);
500 }
501
502 #[test]
503 fn immediate_dominator_on_diamond() {
504 let mut graph = TestGraph::default();
506 let a = graph.make_node(());
507 let b = graph.make_node(());
508 let c = graph.make_node(());
509 let d = graph.make_node(());
510 graph.make_edge(a, b, ());
511 graph.make_edge(a, c, ());
512 graph.make_edge(b, d, ());
513 graph.make_edge(c, d, ());
514
515 let tree = compute_dominators(&graph, a);
516
517 assert_eq!(tree.immediate_dominator(b), Some(a));
518 assert_eq!(tree.immediate_dominator(c), Some(a));
519 assert_eq!(tree.immediate_dominator(d), Some(a));
520 assert_eq!(tree.immediate_dominator(a), None);
521 }
522
523 #[test]
524 fn dominator_frontier_on_diamond() {
525 let mut graph = TestGraph::default();
529 let a = graph.make_node(());
530 let b = graph.make_node(());
531 let c = graph.make_node(());
532 let d = graph.make_node(());
533 graph.make_edge(a, b, ());
534 graph.make_edge(a, c, ());
535 graph.make_edge(b, d, ());
536 graph.make_edge(c, d, ());
537
538 let tree = compute_dominators(&graph, a);
539 let df = tree.dominator_frontier();
540
541 assert_eq!(df[&a], HashSet::default());
542 assert_eq!(df[&b], HashSet::from_iter([d]));
543 assert_eq!(df[&c], HashSet::from_iter([d]));
544 assert_eq!(df[&d], HashSet::default());
545 }
546
547 #[test]
548 fn dominator_frontier_on_loop() {
549 let mut graph = TestGraph::default();
553 let a = graph.make_node(());
554 let b = graph.make_node(());
555 let c = graph.make_node(());
556 let d = graph.make_node(());
557 graph.make_edge(a, b, ());
558 graph.make_edge(b, c, ());
559 graph.make_edge(c, b, ());
560 graph.make_edge(b, d, ());
561
562 let tree = compute_dominators(&graph, a);
563 let df = tree.dominator_frontier();
564
565 assert_eq!(df[&a], HashSet::default());
566 assert_eq!(df[&b], HashSet::from_iter([b]));
567 assert_eq!(df[&c], HashSet::from_iter([b]));
568 assert_eq!(df[&d], HashSet::default());
569 }
570
571 #[test]
572 fn dominator_tree_children_on_diamond() {
573 let mut graph = TestGraph::default();
575 let a = graph.make_node(());
576 let b = graph.make_node(());
577 let c = graph.make_node(());
578 let d = graph.make_node(());
579 graph.make_edge(a, b, ());
580 graph.make_edge(a, c, ());
581 graph.make_edge(b, d, ());
582 graph.make_edge(c, d, ());
583
584 let tree = compute_dominators(&graph, a);
585
586 let mut a_children: Vec<_> = tree.children_of(a).to_vec();
587 a_children.sort_by_key(|id| Into::<usize>::into(*id));
588 assert_eq!(a_children, vec![b, c, d]);
589 assert!(tree.children_of(d).is_empty());
590 }
591}