1 // Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Algorithm citation:
12 //! A Simple, Fast Dominance Algorithm.
13 //! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
14 //! Rice Computer Science TS-06-33870
15 //! <https://www.cs.rice.edu/~keith/EMBED/dom.pdf>
17 use super::super::indexed_vec::{Idx, IndexVec};
18 use super::iterate::reverse_post_order;
19 use super::ControlFlowGraph;
26 pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
27 let start_node = graph.start_node();
28 let rpo = reverse_post_order(graph, start_node);
29 dominators_given_rpo(graph, &rpo)
32 pub fn dominators_given_rpo<G: ControlFlowGraph>(
35 ) -> Dominators<G::Node> {
36 let start_node = graph.start_node();
37 assert_eq!(rpo[0], start_node);
39 // compute the post order index (rank) for each node
40 let mut post_order_rank: IndexVec<G::Node, usize> =
41 IndexVec::from_elem_n(usize::default(), graph.num_nodes());
42 for (index, node) in rpo.iter().rev().cloned().enumerate() {
43 post_order_rank[node] = index;
46 let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
47 IndexVec::from_elem_n(Option::default(), graph.num_nodes());
48 immediate_dominators[start_node] = Some(start_node);
50 let mut changed = true;
54 for &node in &rpo[1..] {
55 let mut new_idom = None;
56 for pred in graph.predecessors(node) {
57 if immediate_dominators[pred].is_some() {
59 // (*) dominators for `pred` have been calculated
60 new_idom = intersect_opt(
62 &immediate_dominators,
69 if new_idom != immediate_dominators[node] {
70 immediate_dominators[node] = new_idom;
82 fn intersect_opt<Node: Idx>(
83 post_order_rank: &IndexVec<Node, usize>,
84 immediate_dominators: &IndexVec<Node, Option<Node>>,
88 match (node1, node2) {
90 (Some(n), None) | (None, Some(n)) => Some(n),
91 (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)),
95 fn intersect<Node: Idx>(
96 post_order_rank: &IndexVec<Node, usize>,
97 immediate_dominators: &IndexVec<Node, Option<Node>>,
101 while node1 != node2 {
102 while post_order_rank[node1] < post_order_rank[node2] {
103 node1 = immediate_dominators[node1].unwrap();
106 while post_order_rank[node2] < post_order_rank[node1] {
107 node2 = immediate_dominators[node2].unwrap();
114 #[derive(Clone, Debug)]
115 pub struct Dominators<N: Idx> {
116 post_order_rank: IndexVec<N, usize>,
117 immediate_dominators: IndexVec<N, Option<N>>,
120 impl<Node: Idx> Dominators<Node> {
121 pub fn is_reachable(&self, node: Node) -> bool {
122 self.immediate_dominators[node].is_some()
125 pub fn immediate_dominator(&self, node: Node) -> Node {
126 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
127 self.immediate_dominators[node].unwrap()
130 pub fn dominators(&self, node: Node) -> Iter<Node> {
131 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
138 pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
139 // FIXME -- could be optimized by using post-order-rank
140 self.dominators(node).any(|n| n == dom)
144 fn all_immediate_dominators(&self) -> &IndexVec<Node, Option<Node>> {
145 &self.immediate_dominators
149 pub struct Iter<'dom, Node: Idx + 'dom> {
150 dominators: &'dom Dominators<Node>,
154 impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
157 fn next(&mut self) -> Option<Self::Item> {
158 if let Some(node) = self.node {
159 let dom = self.dominators.immediate_dominator(node);
161 self.node = None; // reached the root
163 self.node = Some(dom);
172 pub struct DominatorTree<N: Idx> {
174 children: IndexVec<N, Vec<N>>,
177 impl<Node: Idx> DominatorTree<Node> {
178 pub fn children(&self, node: Node) -> &[Node] {
183 impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
184 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
195 struct DominatorTreeNode<'tree, Node: Idx> {
196 tree: &'tree DominatorTree<Node>,
200 impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
201 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
202 let subtrees: Vec<_> = self.tree
205 .map(|&child| DominatorTreeNode {