1 //! Finding the dominators in a control-flow graph.
3 //! Algorithm based on Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy,
4 //! "A Simple, Fast Dominance Algorithm",
5 //! Rice Computer Science TS-06-33870,
6 //! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>.
8 use super::iterate
::reverse_post_order
;
9 use super::ControlFlowGraph
;
10 use rustc_index
::vec
::{Idx, IndexVec}
;
11 use std
::borrow
::BorrowMut
;
16 pub fn dominators
<G
: ControlFlowGraph
>(graph
: G
) -> Dominators
<G
::Node
> {
17 let start_node
= graph
.start_node();
18 let rpo
= reverse_post_order(&graph
, start_node
);
19 dominators_given_rpo(graph
, &rpo
)
22 fn dominators_given_rpo
<G
: ControlFlowGraph
+ BorrowMut
<G
>>(
25 ) -> Dominators
<G
::Node
> {
26 let start_node
= graph
.borrow().start_node();
27 assert_eq
!(rpo
[0], start_node
);
29 // compute the post order index (rank) for each node
30 let mut post_order_rank
: IndexVec
<G
::Node
, usize> =
31 (0..graph
.borrow().num_nodes()).map(|_
| 0).collect();
32 for (index
, node
) in rpo
.iter().rev().cloned().enumerate() {
33 post_order_rank
[node
] = index
;
36 let mut immediate_dominators
: IndexVec
<G
::Node
, Option
<G
::Node
>> =
37 (0..graph
.borrow().num_nodes()).map(|_
| None
).collect();
38 immediate_dominators
[start_node
] = Some(start_node
);
40 let mut changed
= true;
44 for &node
in &rpo
[1..] {
45 let mut new_idom
= None
;
46 for pred
in graph
.borrow_mut().predecessors(node
) {
47 if immediate_dominators
[pred
].is_some() {
48 // (*) dominators for `pred` have been calculated
49 new_idom
= Some(if let Some(new_idom
) = new_idom
{
50 intersect(&post_order_rank
, &immediate_dominators
, new_idom
, pred
)
57 if new_idom
!= immediate_dominators
[node
] {
58 immediate_dominators
[node
] = new_idom
;
64 Dominators { post_order_rank, immediate_dominators }
67 fn intersect
<Node
: Idx
>(
68 post_order_rank
: &IndexVec
<Node
, usize>,
69 immediate_dominators
: &IndexVec
<Node
, Option
<Node
>>,
73 while node1
!= node2
{
74 while post_order_rank
[node1
] < post_order_rank
[node2
] {
75 node1
= immediate_dominators
[node1
].unwrap();
78 while post_order_rank
[node2
] < post_order_rank
[node1
] {
79 node2
= immediate_dominators
[node2
].unwrap();
86 #[derive(Clone, Debug)]
87 pub struct Dominators
<N
: Idx
> {
88 post_order_rank
: IndexVec
<N
, usize>,
89 immediate_dominators
: IndexVec
<N
, Option
<N
>>,
92 impl<Node
: Idx
> Dominators
<Node
> {
93 pub fn is_reachable(&self, node
: Node
) -> bool
{
94 self.immediate_dominators
[node
].is_some()
97 pub fn immediate_dominator(&self, node
: Node
) -> Node
{
98 assert
!(self.is_reachable(node
), "node {:?} is not reachable", node
);
99 self.immediate_dominators
[node
].unwrap()
102 pub fn dominators(&self, node
: Node
) -> Iter
<'_
, Node
> {
103 assert
!(self.is_reachable(node
), "node {:?} is not reachable", node
);
104 Iter { dominators: self, node: Some(node) }
107 pub fn is_dominated_by(&self, node
: Node
, dom
: Node
) -> bool
{
108 // FIXME -- could be optimized by using post-order-rank
109 self.dominators(node
).any(|n
| n
== dom
)
113 pub struct Iter
<'dom
, Node
: Idx
> {
114 dominators
: &'dom Dominators
<Node
>,
118 impl<'dom
, Node
: Idx
> Iterator
for Iter
<'dom
, Node
> {
121 fn next(&mut self) -> Option
<Self::Item
> {
122 if let Some(node
) = self.node
{
123 let dom
= self.dominators
.immediate_dominator(node
);
125 self.node
= None
; // reached the root
127 self.node
= Some(dom
);