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::ControlFlowGraph;
18 use super::iterate::reverse_post_order;
19 use super::super::indexed_vec::{IndexVec, Idx};
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>(graph: &G,
34 -> Dominators<G::Node> {
35 let start_node = graph.start_node();
36 assert_eq!(rpo[0], start_node);
38 // compute the post order index (rank) for each node
39 let mut post_order_rank: IndexVec<G::Node, usize> = IndexVec::from_elem_n(usize::default(),
41 for (index, node) in rpo.iter().rev().cloned().enumerate() {
42 post_order_rank[node] = index;
45 let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
46 IndexVec::from_elem_n(Option::default(), graph.num_nodes());
47 immediate_dominators[start_node] = Some(start_node);
49 let mut changed = true;
53 for &node in &rpo[1..] {
54 let mut new_idom = None;
55 for pred in graph.predecessors(node) {
56 if immediate_dominators[pred].is_some() {
58 // (*) dominators for `pred` have been calculated
59 new_idom = intersect_opt(&post_order_rank,
60 &immediate_dominators,
66 if new_idom != immediate_dominators[node] {
67 immediate_dominators[node] = new_idom;
79 fn intersect_opt<Node: Idx>(post_order_rank: &IndexVec<Node, usize>,
80 immediate_dominators: &IndexVec<Node, Option<Node>>,
84 match (node1, node2) {
86 (Some(n), None) | (None, Some(n)) => Some(n),
87 (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)),
91 fn intersect<Node: Idx>(post_order_rank: &IndexVec<Node, usize>,
92 immediate_dominators: &IndexVec<Node, Option<Node>>,
96 while node1 != node2 {
97 while post_order_rank[node1] < post_order_rank[node2] {
98 node1 = immediate_dominators[node1].unwrap();
101 while post_order_rank[node2] < post_order_rank[node1] {
102 node2 = immediate_dominators[node2].unwrap();
108 #[derive(Clone, Debug)]
109 pub struct Dominators<N: Idx> {
110 post_order_rank: IndexVec<N, usize>,
111 immediate_dominators: IndexVec<N, Option<N>>,
114 impl<Node: Idx> Dominators<Node> {
115 pub fn is_reachable(&self, node: Node) -> bool {
116 self.immediate_dominators[node].is_some()
119 pub fn immediate_dominator(&self, node: Node) -> Node {
120 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
121 self.immediate_dominators[node].unwrap()
124 pub fn dominators(&self, node: Node) -> Iter<Node> {
125 assert!(self.is_reachable(node), "node {:?} is not reachable", node);
132 pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
133 // FIXME -- could be optimized by using post-order-rank
134 self.dominators(node).any(|n| n == dom)
138 fn all_immediate_dominators(&self) -> &IndexVec<Node, Option<Node>> {
139 &self.immediate_dominators
143 pub struct Iter<'dom, Node: Idx + 'dom> {
144 dominators: &'dom Dominators<Node>,
148 impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
151 fn next(&mut self) -> Option<Self::Item> {
152 if let Some(node) = self.node {
153 let dom = self.dominators.immediate_dominator(node);
155 self.node = None; // reached the root
157 self.node = Some(dom);
166 pub struct DominatorTree<N: Idx> {
168 children: IndexVec<N, Vec<N>>,
171 impl<Node: Idx> DominatorTree<Node> {
172 pub fn children(&self, node: Node) -> &[Node] {
177 impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
178 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
179 fmt::Debug::fmt(&DominatorTreeNode {
187 struct DominatorTreeNode<'tree, Node: Idx> {
188 tree: &'tree DominatorTree<Node>,
192 impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
193 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
194 let subtrees: Vec<_> = self.tree