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
5 //! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>
7 use super::iterate
::reverse_post_order
;
8 use super::ControlFlowGraph
;
9 use rustc_index
::vec
::{Idx, IndexVec}
;
10 use std
::borrow
::BorrowMut
;
15 pub fn dominators
<G
: ControlFlowGraph
>(graph
: G
) -> Dominators
<G
::Node
> {
16 let start_node
= graph
.start_node();
17 let rpo
= reverse_post_order(&graph
, start_node
);
18 dominators_given_rpo(graph
, &rpo
)
21 fn dominators_given_rpo
<G
: ControlFlowGraph
+ BorrowMut
<G
>>(
24 ) -> Dominators
<G
::Node
> {
25 let start_node
= graph
.borrow().start_node();
26 assert_eq
!(rpo
[0], start_node
);
28 // compute the post order index (rank) for each node
29 let mut post_order_rank
: IndexVec
<G
::Node
, usize> =
30 (0..graph
.borrow().num_nodes()).map(|_
| 0).collect();
31 for (index
, node
) in rpo
.iter().rev().cloned().enumerate() {
32 post_order_rank
[node
] = index
;
35 let mut immediate_dominators
: IndexVec
<G
::Node
, Option
<G
::Node
>> =
36 (0..graph
.borrow().num_nodes()).map(|_
| None
).collect();
37 immediate_dominators
[start_node
] = Some(start_node
);
39 let mut changed
= true;
43 for &node
in &rpo
[1..] {
44 let mut new_idom
= None
;
45 for pred
in graph
.borrow_mut().predecessors(node
) {
46 if immediate_dominators
[pred
].is_some() {
47 // (*) dominators for `pred` have been calculated
48 new_idom
= Some(if let Some(new_idom
) = new_idom
{
49 intersect(&post_order_rank
, &immediate_dominators
, new_idom
, pred
)
56 if new_idom
!= immediate_dominators
[node
] {
57 immediate_dominators
[node
] = new_idom
;
63 Dominators { post_order_rank, immediate_dominators }
66 fn intersect
<Node
: Idx
>(
67 post_order_rank
: &IndexVec
<Node
, usize>,
68 immediate_dominators
: &IndexVec
<Node
, Option
<Node
>>,
72 while node1
!= node2
{
73 while post_order_rank
[node1
] < post_order_rank
[node2
] {
74 node1
= immediate_dominators
[node1
].unwrap();
77 while post_order_rank
[node2
] < post_order_rank
[node1
] {
78 node2
= immediate_dominators
[node2
].unwrap();
85 #[derive(Clone, Debug)]
86 pub struct Dominators
<N
: Idx
> {
87 post_order_rank
: IndexVec
<N
, usize>,
88 immediate_dominators
: IndexVec
<N
, Option
<N
>>,
91 impl<Node
: Idx
> Dominators
<Node
> {
92 pub fn is_reachable(&self, node
: Node
) -> bool
{
93 self.immediate_dominators
[node
].is_some()
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()
101 pub fn dominators(&self, node
: Node
) -> Iter
<'_
, Node
> {
102 assert
!(self.is_reachable(node
), "node {:?} is not reachable", node
);
103 Iter { dominators: self, node: Some(node) }
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
)
112 pub struct Iter
<'dom
, Node
: Idx
> {
113 dominators
: &'dom Dominators
<Node
>,
117 impl<'dom
, Node
: Idx
> Iterator
for Iter
<'dom
, Node
> {
120 fn next(&mut self) -> Option
<Self::Item
> {
121 if let Some(node
) = self.node
{
122 let dom
= self.dominators
.immediate_dominator(node
);
124 self.node
= None
; // reached the root
126 self.node
= Some(dom
);