]> git.proxmox.com Git - rustc.git/blame - src/librustc_data_structures/graph/dominators/mod.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / librustc_data_structures / graph / dominators / mod.rs
CommitLineData
3157f602
XL
1//! Algorithm citation:
2//! A Simple, Fast Dominance Algorithm.
3//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
4//! Rice Computer Science TS-06-33870
ff7c6d11 5//! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>
3157f602 6
3157f602 7use super::iterate::reverse_post_order;
8faf50e0 8use super::ControlFlowGraph;
dfeec247 9use rustc_index::vec::{Idx, IndexVec};
60c5eb7d 10use std::borrow::BorrowMut;
3157f602 11
3157f602 12#[cfg(test)]
416331ca 13mod tests;
3157f602 14
60c5eb7d 15pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
3157f602 16 let start_node = graph.start_node();
60c5eb7d 17 let rpo = reverse_post_order(&graph, start_node);
3157f602
XL
18 dominators_given_rpo(graph, &rpo)
19}
20
60c5eb7d
XL
21fn dominators_given_rpo<G: ControlFlowGraph + BorrowMut<G>>(
22 mut graph: G,
8faf50e0
XL
23 rpo: &[G::Node],
24) -> Dominators<G::Node> {
60c5eb7d 25 let start_node = graph.borrow().start_node();
3157f602
XL
26 assert_eq!(rpo[0], start_node);
27
28 // compute the post order index (rank) for each node
8faf50e0 29 let mut post_order_rank: IndexVec<G::Node, usize> =
60c5eb7d 30 (0..graph.borrow().num_nodes()).map(|_| 0).collect();
3157f602
XL
31 for (index, node) in rpo.iter().rev().cloned().enumerate() {
32 post_order_rank[node] = index;
33 }
34
35 let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
60c5eb7d 36 (0..graph.borrow().num_nodes()).map(|_| None).collect();
3157f602
XL
37 immediate_dominators[start_node] = Some(start_node);
38
39 let mut changed = true;
40 while changed {
41 changed = false;
42
43 for &node in &rpo[1..] {
44 let mut new_idom = None;
60c5eb7d 45 for pred in graph.borrow_mut().predecessors(node) {
3157f602 46 if immediate_dominators[pred].is_some() {
3157f602 47 // (*) dominators for `pred` have been calculated
e74abb32
XL
48 new_idom = Some(if let Some(new_idom) = new_idom {
49 intersect(&post_order_rank, &immediate_dominators, new_idom, pred)
50 } else {
51 pred
52 });
3157f602
XL
53 }
54 }
55
56 if new_idom != immediate_dominators[node] {
57 immediate_dominators[node] = new_idom;
58 changed = true;
59 }
60 }
61 }
62
dfeec247 63 Dominators { post_order_rank, immediate_dominators }
3157f602
XL
64}
65
8faf50e0
XL
66fn intersect<Node: Idx>(
67 post_order_rank: &IndexVec<Node, usize>,
68 immediate_dominators: &IndexVec<Node, Option<Node>>,
69 mut node1: Node,
70 mut node2: Node,
71) -> Node {
3157f602
XL
72 while node1 != node2 {
73 while post_order_rank[node1] < post_order_rank[node2] {
74 node1 = immediate_dominators[node1].unwrap();
75 }
76
77 while post_order_rank[node2] < post_order_rank[node1] {
78 node2 = immediate_dominators[node2].unwrap();
79 }
80 }
b7449926
XL
81
82 node1
3157f602
XL
83}
84
85#[derive(Clone, Debug)]
86pub struct Dominators<N: Idx> {
87 post_order_rank: IndexVec<N, usize>,
88 immediate_dominators: IndexVec<N, Option<N>>,
89}
90
91impl<Node: Idx> Dominators<Node> {
92 pub fn is_reachable(&self, node: Node) -> bool {
93 self.immediate_dominators[node].is_some()
94 }
95
96 pub fn immediate_dominator(&self, node: Node) -> Node {
97 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
98 self.immediate_dominators[node].unwrap()
99 }
100
9fa01778 101 pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
3157f602 102 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
dfeec247 103 Iter { dominators: self, node: Some(node) }
3157f602
XL
104 }
105
106 pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
107 // FIXME -- could be optimized by using post-order-rank
108 self.dominators(node).any(|n| n == dom)
109 }
3157f602
XL
110}
111
9fa01778 112pub struct Iter<'dom, Node: Idx> {
3157f602
XL
113 dominators: &'dom Dominators<Node>,
114 node: Option<Node>,
115}
116
117impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
118 type Item = Node;
119
120 fn next(&mut self) -> Option<Self::Item> {
121 if let Some(node) = self.node {
122 let dom = self.dominators.immediate_dominator(node);
123 if dom == node {
124 self.node = None; // reached the root
125 } else {
126 self.node = Some(dom);
127 }
ba9703b0 128 Some(node)
3157f602 129 } else {
ba9703b0 130 None
3157f602
XL
131 }
132 }
133}