Skip to content

Commit 03f7a7b

Browse files
committed
add graph algorithms. add dominator to mir
1 parent fe96928 commit 03f7a7b

File tree

14 files changed

+868
-3
lines changed

14 files changed

+868
-3
lines changed

src/librustc/mir/cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use mir::repr::{Mir, BasicBlock};
1515

1616
use rustc_serialize as serialize;
1717

18-
#[derive(Clone)]
18+
#[derive(Clone, Debug)]
1919
pub struct Cache {
2020
predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
2121
}

src/librustc/mir/repr.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use graphviz::IntoCow;
1212
use middle::const_val::ConstVal;
1313
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
1414
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
15+
use rustc_data_structures::graph_algorithms::dominators::{Dominators, dominators};
16+
use rustc_data_structures::graph_algorithms::{Graph, GraphPredecessors, GraphSuccessors};
1517
use hir::def_id::DefId;
1618
use ty::subst::Substs;
1719
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@@ -24,6 +26,7 @@ use std::cell::Ref;
2426
use std::fmt::{self, Debug, Formatter, Write};
2527
use std::{iter, u32};
2628
use std::ops::{Index, IndexMut};
29+
use std::vec::IntoIter;
2730
use syntax::ast::{self, Name};
2831
use syntax::codemap::Span;
2932

@@ -54,7 +57,7 @@ macro_rules! newtype_index {
5457
}
5558

5659
/// Lowered representation of a single function.
57-
#[derive(Clone, RustcEncodable, RustcDecodable)]
60+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
5861
pub struct Mir<'tcx> {
5962
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
6063
/// that indexes into this vector.
@@ -145,6 +148,11 @@ impl<'tcx> Mir<'tcx> {
145148
Ref::map(self.predecessors(), |p| &p[bb])
146149
}
147150

151+
#[inline]
152+
pub fn dominators(&self) -> Dominators<Self> {
153+
dominators(self)
154+
}
155+
148156
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
149157
/// to their index in the whole list of locals. This is useful if you
150158
/// want to treat all locals the same instead of repeating yourself.
@@ -1190,3 +1198,33 @@ fn node_to_string(node_id: ast::NodeId) -> String {
11901198
fn item_path_str(def_id: DefId) -> String {
11911199
ty::tls::with(|tcx| tcx.item_path_str(def_id))
11921200
}
1201+
1202+
impl<'tcx> Graph for Mir<'tcx> {
1203+
1204+
type Node = BasicBlock;
1205+
1206+
fn num_nodes(&self) -> usize { self.basic_blocks.len() }
1207+
1208+
fn start_node(&self) -> Self::Node { START_BLOCK }
1209+
1210+
fn predecessors<'graph>(&'graph self, node: Self::Node)
1211+
-> <Self as GraphPredecessors<'graph>>::Iter
1212+
{
1213+
self.predecessors_for(node).clone().into_iter()
1214+
}
1215+
fn successors<'graph>(&'graph self, node: Self::Node)
1216+
-> <Self as GraphSuccessors<'graph>>::Iter
1217+
{
1218+
self.basic_blocks[node].terminator().successors().into_owned().into_iter()
1219+
}
1220+
}
1221+
1222+
impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> {
1223+
type Item = BasicBlock;
1224+
type Iter = IntoIter<BasicBlock>;
1225+
}
1226+
1227+
impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> {
1228+
type Item = BasicBlock;
1229+
type Iter = IntoIter<BasicBlock>;
1230+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
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.
4+
//
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.
10+
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
16+
17+
use super::Graph;
18+
use super::iterate::reverse_post_order;
19+
use super::super::indexed_vec::{IndexVec, Idx};
20+
21+
use std::fmt;
22+
23+
#[cfg(test)]
24+
mod test;
25+
26+
pub fn dominators<G: Graph>(graph: &G) -> Dominators<G> {
27+
let start_node = graph.start_node();
28+
let rpo = reverse_post_order(graph, start_node);
29+
dominators_given_rpo(graph, &rpo)
30+
}
31+
32+
pub fn dominators_given_rpo<G: Graph>(graph: &G, rpo: &[G::Node]) -> Dominators<G> {
33+
let start_node = graph.start_node();
34+
assert_eq!(rpo[0], start_node);
35+
36+
// compute the post order index (rank) for each node
37+
let mut post_order_rank: IndexVec<G::Node, usize> = IndexVec::from_elem_n(usize::default(),
38+
graph.num_nodes());
39+
for (index, node) in rpo.iter().rev().cloned().enumerate() {
40+
post_order_rank[node] = index;
41+
}
42+
43+
let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
44+
IndexVec::from_elem_n(Option::default(), graph.num_nodes());
45+
immediate_dominators[start_node] = Some(start_node);
46+
47+
let mut changed = true;
48+
while changed {
49+
changed = false;
50+
51+
for &node in &rpo[1..] {
52+
let mut new_idom = None;
53+
for pred in graph.predecessors(node) {
54+
if immediate_dominators[pred].is_some() {
55+
// (*)
56+
// (*) dominators for `pred` have been calculated
57+
new_idom = intersect_opt::<G>(&post_order_rank,
58+
&immediate_dominators,
59+
new_idom,
60+
Some(pred));
61+
}
62+
}
63+
64+
if new_idom != immediate_dominators[node] {
65+
immediate_dominators[node] = new_idom;
66+
changed = true;
67+
}
68+
}
69+
}
70+
71+
Dominators {
72+
post_order_rank: post_order_rank,
73+
immediate_dominators: immediate_dominators,
74+
}
75+
}
76+
77+
fn intersect_opt<G: Graph>(post_order_rank: &IndexVec<G::Node, usize>,
78+
immediate_dominators: &IndexVec<G::Node, Option<G::Node>>,
79+
node1: Option<G::Node>,
80+
node2: Option<G::Node>)
81+
-> Option<G::Node> {
82+
match (node1, node2) {
83+
(None, None) => None,
84+
(Some(n), None) | (None, Some(n)) => Some(n),
85+
(Some(n1), Some(n2)) => Some(intersect::<G>(post_order_rank, immediate_dominators, n1, n2)),
86+
}
87+
}
88+
89+
fn intersect<G: Graph>(post_order_rank: &IndexVec<G::Node, usize>,
90+
immediate_dominators: &IndexVec<G::Node, Option<G::Node>>,
91+
mut node1: G::Node,
92+
mut node2: G::Node)
93+
-> G::Node {
94+
while node1 != node2 {
95+
while post_order_rank[node1] < post_order_rank[node2] {
96+
node1 = immediate_dominators[node1].unwrap();
97+
}
98+
99+
while post_order_rank[node2] < post_order_rank[node1] {
100+
node2 = immediate_dominators[node2].unwrap();
101+
}
102+
}
103+
return node1;
104+
}
105+
106+
#[derive(Clone, Debug)]
107+
pub struct Dominators<G: Graph> {
108+
post_order_rank: IndexVec<G::Node, usize>,
109+
immediate_dominators: IndexVec<G::Node, Option<G::Node>>,
110+
}
111+
112+
impl<G: Graph> Dominators<G> {
113+
pub fn is_reachable(&self, node: G::Node) -> bool {
114+
self.immediate_dominators[node].is_some()
115+
}
116+
117+
pub fn immediate_dominator(&self, node: G::Node) -> G::Node {
118+
assert!(self.is_reachable(node), "node {:?} is not reachable", node);
119+
self.immediate_dominators[node].unwrap()
120+
}
121+
122+
pub fn dominators(&self, node: G::Node) -> Iter<G> {
123+
assert!(self.is_reachable(node), "node {:?} is not reachable", node);
124+
Iter {
125+
dominators: self,
126+
node: Some(node),
127+
}
128+
}
129+
130+
pub fn is_dominated_by(&self, node: G::Node, dom: G::Node) -> bool {
131+
// FIXME -- could be optimized by using post-order-rank
132+
self.dominators(node).any(|n| n == dom)
133+
}
134+
135+
pub fn mutual_dominator_node(&self, node1: G::Node, node2: G::Node) -> G::Node {
136+
assert!(self.is_reachable(node1),
137+
"node {:?} is not reachable",
138+
node1);
139+
assert!(self.is_reachable(node2),
140+
"node {:?} is not reachable",
141+
node2);
142+
intersect::<G>(&self.post_order_rank,
143+
&self.immediate_dominators,
144+
node1,
145+
node2)
146+
}
147+
148+
pub fn mutual_dominator<I>(&self, iter: I) -> Option<G::Node>
149+
where I: IntoIterator<Item = G::Node>
150+
{
151+
let mut iter = iter.into_iter();
152+
iter.next()
153+
.map(|dom| iter.fold(dom, |dom, node| self.mutual_dominator_node(dom, node)))
154+
}
155+
156+
pub fn all_immediate_dominators(&self) -> &IndexVec<G::Node, Option<G::Node>> {
157+
&self.immediate_dominators
158+
}
159+
160+
pub fn dominator_tree(&self) -> DominatorTree<G> {
161+
let elem: Vec<G::Node> = Vec::new();
162+
let mut children: IndexVec<G::Node, Vec<G::Node>> =
163+
IndexVec::from_elem_n(elem, self.immediate_dominators.len());
164+
let mut root = None;
165+
for (index, immed_dom) in self.immediate_dominators.iter().enumerate() {
166+
let node = G::Node::new(index);
167+
match *immed_dom {
168+
None => {
169+
// node not reachable
170+
}
171+
Some(immed_dom) => {
172+
if node == immed_dom {
173+
root = Some(node);
174+
} else {
175+
children[immed_dom].push(node);
176+
}
177+
}
178+
}
179+
}
180+
DominatorTree {
181+
root: root.unwrap(),
182+
children: children,
183+
}
184+
}
185+
}
186+
187+
pub struct Iter<'dom, G: Graph + 'dom> {
188+
dominators: &'dom Dominators<G>,
189+
node: Option<G::Node>,
190+
}
191+
192+
impl<'dom, G: Graph> Iterator for Iter<'dom, G> {
193+
type Item = G::Node;
194+
195+
fn next(&mut self) -> Option<Self::Item> {
196+
if let Some(node) = self.node {
197+
let dom = self.dominators.immediate_dominator(node);
198+
if dom == node {
199+
self.node = None; // reached the root
200+
} else {
201+
self.node = Some(dom);
202+
}
203+
return Some(node);
204+
} else {
205+
return None;
206+
}
207+
}
208+
}
209+
210+
pub struct DominatorTree<G: Graph> {
211+
root: G::Node,
212+
children: IndexVec<G::Node, Vec<G::Node>>,
213+
}
214+
215+
impl<G: Graph> DominatorTree<G> {
216+
pub fn root(&self) -> G::Node {
217+
self.root
218+
}
219+
220+
pub fn children(&self, node: G::Node) -> &[G::Node] {
221+
&self.children[node]
222+
}
223+
224+
pub fn iter_children_of(&self, node: G::Node) -> IterChildrenOf<G> {
225+
IterChildrenOf {
226+
tree: self,
227+
stack: vec![node],
228+
}
229+
}
230+
}
231+
232+
pub struct IterChildrenOf<'iter, G: Graph + 'iter> {
233+
tree: &'iter DominatorTree<G>,
234+
stack: Vec<G::Node>,
235+
}
236+
237+
impl<'iter, G: Graph> Iterator for IterChildrenOf<'iter, G> {
238+
type Item = G::Node;
239+
240+
fn next(&mut self) -> Option<G::Node> {
241+
if let Some(node) = self.stack.pop() {
242+
self.stack.extend(self.tree.children(node));
243+
Some(node)
244+
} else {
245+
None
246+
}
247+
}
248+
}
249+
250+
impl<G: Graph> fmt::Debug for DominatorTree<G> {
251+
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
252+
fmt::Debug::fmt(&DominatorTreeNode {
253+
tree: self,
254+
node: self.root,
255+
},
256+
fmt)
257+
}
258+
}
259+
260+
struct DominatorTreeNode<'tree, G: Graph + 'tree> {
261+
tree: &'tree DominatorTree<G>,
262+
node: G::Node,
263+
}
264+
265+
impl<'tree, G: Graph> fmt::Debug for DominatorTreeNode<'tree, G> {
266+
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
267+
let subtrees: Vec<_> = self.tree
268+
.children(self.node)
269+
.iter()
270+
.map(|&child| {
271+
DominatorTreeNode {
272+
tree: self.tree,
273+
node: child,
274+
}
275+
})
276+
.collect();
277+
fmt.debug_tuple("")
278+
.field(&self.node)
279+
.field(&subtrees)
280+
.finish()
281+
}
282+
}

0 commit comments

Comments
 (0)