Skip to content

Commit bfbcec6

Browse files
committedJun 22, 2016
add graph algorithms. add dominator to mir
1 parent fe96928 commit bfbcec6

File tree

15 files changed

+879
-3
lines changed

15 files changed

+879
-3
lines changed
 

‎rustc_data_structures

2.34 MB
Binary file not shown.

‎src/librustc/mir/cache.rs

Lines changed: 1 addition & 1 deletion
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

Lines changed: 39 additions & 1 deletion
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+
}
Lines changed: 282 additions & 0 deletions
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+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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+
use super::super::test::TestGraph;
12+
13+
use super::*;
14+
15+
#[test]
16+
fn diamond() {
17+
let graph = TestGraph::new(0, &[
18+
(0, 1),
19+
(0, 2),
20+
(1, 3),
21+
(2, 3),
22+
]);
23+
24+
let dominators = dominators(&graph);
25+
// assert_eq!(&dominators.all_immediate_dominators().vec[..],
26+
// &[Some(0),
27+
// Some(0),
28+
// Some(0),
29+
// Some(0)]);
30+
let immediate_dominators = dominators.all_immediate_dominators();
31+
assert_eq!(immediate_dominators[0], Some(0));
32+
assert_eq!(immediate_dominators[1], Some(0));
33+
assert_eq!(immediate_dominators[2], Some(0));
34+
assert_eq!(immediate_dominators[3], Some(0));
35+
}
36+
37+
#[test]
38+
fn paper() {
39+
// example from the paper:
40+
let graph = TestGraph::new(6, &[
41+
(6, 5),
42+
(6, 4),
43+
(5, 1),
44+
(4, 2),
45+
(4, 3),
46+
(1, 2),
47+
(2, 3),
48+
(3, 2),
49+
(2, 1),
50+
]);
51+
52+
let dominators = dominators(&graph);
53+
// assert_eq!(&dominators.all_immediate_dominators().vec[..],
54+
// &[None, // <-- note that 0 is not in graph
55+
// Some(6), Some(6), Some(6),
56+
// Some(6), Some(6), Some(6)]);
57+
let immediate_dominators = dominators.all_immediate_dominators();
58+
assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph
59+
assert_eq!(immediate_dominators[1], Some(6));
60+
assert_eq!(immediate_dominators[2], Some(6));
61+
assert_eq!(immediate_dominators[3], Some(6));
62+
assert_eq!(immediate_dominators[4], Some(6));
63+
assert_eq!(immediate_dominators[5], Some(6));
64+
assert_eq!(immediate_dominators[6], Some(6));
65+
}
66+
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
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+
use super::Graph;
12+
use super::super::indexed_vec::IndexVec;
13+
14+
#[cfg(test)]
15+
mod test;
16+
17+
pub fn post_order_from<G: Graph>(graph: &G, start_node: G::Node) -> Vec<G::Node> {
18+
post_order_from_to(graph, start_node, None)
19+
}
20+
21+
pub fn post_order_from_to<G: Graph>(graph: &G,
22+
start_node: G::Node,
23+
end_node: Option<G::Node>)
24+
-> Vec<G::Node> {
25+
let mut visited: IndexVec<G::Node, bool> = IndexVec::from_elem_n(false, graph.num_nodes());
26+
let mut result: Vec<G::Node> = Vec::with_capacity(graph.num_nodes());
27+
if let Some(end_node) = end_node {
28+
visited[end_node] = true;
29+
}
30+
post_order_walk(graph, start_node, &mut result, &mut visited);
31+
result
32+
}
33+
34+
fn post_order_walk<G: Graph>(graph: &G,
35+
node: G::Node,
36+
result: &mut Vec<G::Node>,
37+
visited: &mut IndexVec<G::Node, bool>) {
38+
if visited[node] {
39+
return;
40+
}
41+
visited[node] = true;
42+
43+
for successor in graph.successors(node) {
44+
post_order_walk(graph, successor, result, visited);
45+
}
46+
47+
result.push(node);
48+
}
49+
50+
pub fn pre_order_walk<G: Graph>(graph: &G,
51+
node: G::Node,
52+
result: &mut Vec<G::Node>,
53+
visited: &mut IndexVec<G::Node, bool>) {
54+
if visited[node] {
55+
return;
56+
}
57+
visited[node] = true;
58+
59+
result.push(node);
60+
61+
for successor in graph.successors(node) {
62+
pre_order_walk(graph, successor, result, visited);
63+
}
64+
}
65+
66+
pub fn reverse_post_order<G: Graph>(graph: &G, start_node: G::Node) -> Vec<G::Node> {
67+
let mut vec = post_order_from(graph, start_node);
68+
vec.reverse();
69+
vec
70+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
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+
use super::super::test::TestGraph;
12+
use super::super::transpose::TransposedGraph;
13+
14+
use super::*;
15+
16+
#[test]
17+
fn diamond_post_order() {
18+
let graph = TestGraph::new(0, &[
19+
(0, 1),
20+
(0, 2),
21+
(1, 3),
22+
(2, 3),
23+
]);
24+
25+
let result = post_order_from(&graph, 0);
26+
assert_eq!(result, vec![3, 1, 2, 0]);
27+
}
28+
29+
30+
#[test]
31+
fn rev_post_order_inner_loop() {
32+
// 0 -> 1 -> 2 -> 3 -> 5
33+
// ^ ^ v |
34+
// | 6 <- 4 |
35+
// +-----------------+
36+
let graph = TestGraph::new(0, &[
37+
(0, 1),
38+
(1, 2),
39+
(2, 3),
40+
(3, 5),
41+
(3, 1),
42+
(2, 4),
43+
(4, 6),
44+
(6, 2),
45+
]);
46+
47+
let rev_graph = TransposedGraph::new(&graph);
48+
49+
let result = post_order_from_to(&rev_graph, 6, Some(2));
50+
assert_eq!(result, vec![4, 6]);
51+
52+
let result = post_order_from_to(&rev_graph, 3, Some(1));
53+
assert_eq!(result, vec![4, 6, 2, 3]);
54+
}
55+
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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+
use super::indexed_vec::Idx;
12+
pub use std::slice::Iter;
13+
14+
pub mod dominators;
15+
pub mod iterate;
16+
pub mod reachable;
17+
mod reference;
18+
pub mod transpose;
19+
20+
#[cfg(test)]
21+
mod test;
22+
23+
pub trait Graph
24+
where Self: for<'graph> GraphPredecessors<'graph, Item=<Self as Graph>::Node>,
25+
Self: for<'graph> GraphSuccessors<'graph, Item=<Self as Graph>::Node>
26+
{
27+
type Node: Idx;
28+
29+
fn num_nodes(&self) -> usize;
30+
fn start_node(&self) -> Self::Node;
31+
fn predecessors<'graph>(&'graph self, node: Self::Node)
32+
-> <Self as GraphPredecessors<'graph>>::Iter;
33+
fn successors<'graph>(&'graph self, node: Self::Node)
34+
-> <Self as GraphSuccessors<'graph>>::Iter;
35+
}
36+
37+
pub trait GraphPredecessors<'graph> {
38+
type Item;
39+
type Iter: Iterator<Item=Self::Item>;
40+
}
41+
42+
pub trait GraphSuccessors<'graph> {
43+
type Item;
44+
type Iter: Iterator<Item=Self::Item>;
45+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
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+
//! Compute reachability using a simple dataflow propagation.
12+
//! Store end-result in a big NxN bit matrix.
13+
14+
use super::Graph;
15+
use super::super::bitvec::BitVector;
16+
use super::iterate::reverse_post_order;
17+
use super::super::indexed_vec::{IndexVec, Idx};
18+
19+
#[cfg(test)]
20+
mod test;
21+
22+
pub fn reachable<G: Graph>(graph: &G)
23+
-> Reachability<G> {
24+
let reverse_post_order = reverse_post_order(graph, graph.start_node());
25+
reachable_given_rpo(graph, &reverse_post_order)
26+
}
27+
28+
pub fn reachable_given_rpo<G: Graph>(graph: &G,
29+
reverse_post_order: &[G::Node])
30+
-> Reachability<G> {
31+
let mut reachability = Reachability::new(graph);
32+
let mut changed = true;
33+
while changed {
34+
changed = false;
35+
for &node in reverse_post_order.iter().rev() {
36+
// every node can reach itself
37+
changed |= reachability.bits[node].insert(node.index());
38+
39+
// and every pred can reach everything node can reach
40+
for pred in graph.predecessors(node) {
41+
let nodes_bits = reachability.bits[node].clone();
42+
changed |= reachability.bits[pred].insert_all(&nodes_bits);
43+
}
44+
}
45+
}
46+
reachability
47+
}
48+
49+
pub struct Reachability<G: Graph> {
50+
bits: IndexVec<G::Node, BitVector>,
51+
}
52+
53+
impl<G: Graph> Reachability<G> {
54+
fn new(graph: &G) -> Self {
55+
let num_nodes = graph.num_nodes();
56+
Reachability {
57+
bits: IndexVec::from_elem_n(BitVector::new(num_nodes), num_nodes),
58+
}
59+
}
60+
61+
pub fn can_reach(&self, source: G::Node, target: G::Node)-> bool {
62+
let bit: usize = target.index();
63+
self.bits[source].contains(bit)
64+
}
65+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
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+
use super::super::test::TestGraph;
12+
13+
use super::*;
14+
15+
#[test]
16+
fn test1() {
17+
// 0 -> 1 -> 2 -> 3
18+
// ^ v
19+
// 6 <- 4 -> 5
20+
let graph = TestGraph::new(0, &[
21+
(0, 1),
22+
(1, 2),
23+
(2, 3),
24+
(2, 4),
25+
(4, 5),
26+
(4, 6),
27+
(6, 1),
28+
]);
29+
let reachable = reachable(&graph);
30+
assert!((0..6).all(|i| reachable.can_reach(0, i)));
31+
assert!((1..6).all(|i| reachable.can_reach(1, i)));
32+
assert!((1..6).all(|i| reachable.can_reach(2, i)));
33+
assert!((1..6).all(|i| reachable.can_reach(4, i)));
34+
assert!((1..6).all(|i| reachable.can_reach(6, i)));
35+
assert!(reachable.can_reach(3, 3));
36+
assert!(!reachable.can_reach(3, 5));
37+
assert!(!reachable.can_reach(5, 3));
38+
}
39+
40+
/// use bigger indices to cross between words in the bit set
41+
#[test]
42+
fn test2() {
43+
// 30 -> 31 -> 32 -> 33
44+
// ^ v
45+
// 36 <- 34 -> 35
46+
let graph = TestGraph::new(30, &[
47+
(30, 31),
48+
(31, 32),
49+
(32, 33),
50+
(32, 34),
51+
(34, 35),
52+
(34, 36),
53+
(36, 31),
54+
]);
55+
let reachable = reachable(&graph);
56+
assert!((30..36).all(|i| reachable.can_reach(30, i)));
57+
assert!((31..36).all(|i| reachable.can_reach(31, i)));
58+
assert!((31..36).all(|i| reachable.can_reach(32, i)));
59+
assert!((31..36).all(|i| reachable.can_reach(34, i)));
60+
assert!((31..36).all(|i| reachable.can_reach(36, i)));
61+
assert!(reachable.can_reach(33, 33));
62+
assert!(!reachable.can_reach(33, 35));
63+
assert!(!reachable.can_reach(35, 33));
64+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
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+
use super::*;
12+
13+
impl<'graph, G: Graph> Graph for &'graph G {
14+
type Node = G::Node;
15+
16+
fn num_nodes(&self) -> usize {
17+
(**self).num_nodes()
18+
}
19+
20+
fn start_node(&self) -> Self::Node {
21+
(**self).start_node()
22+
}
23+
24+
fn predecessors<'iter>(&'iter self, node: Self::Node)
25+
-> <Self as GraphPredecessors<'iter>>::Iter {
26+
(**self).predecessors(node)
27+
}
28+
29+
fn successors<'iter>(&'iter self, node: Self::Node)
30+
-> <Self as GraphSuccessors<'iter>>::Iter {
31+
(**self).successors(node)
32+
}
33+
}
34+
35+
impl<'iter, 'graph, G: Graph> GraphPredecessors<'iter> for &'graph G {
36+
type Item = G::Node;
37+
type Iter = <G as GraphPredecessors<'iter>>::Iter;
38+
}
39+
40+
impl<'iter, 'graph, G: Graph> GraphSuccessors<'iter> for &'graph G {
41+
type Item = G::Node;
42+
type Iter = <G as GraphSuccessors<'iter>>::Iter;
43+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
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+
use std::collections::HashMap;
12+
use std::cmp::max;
13+
use std::slice;
14+
use std::iter;
15+
16+
use super::{Graph, GraphPredecessors, GraphSuccessors};
17+
18+
pub struct TestGraph {
19+
num_nodes: usize,
20+
start_node: usize,
21+
successors: HashMap<usize, Vec<usize>>,
22+
predecessors: HashMap<usize, Vec<usize>>,
23+
}
24+
25+
impl TestGraph {
26+
pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self {
27+
let mut graph = TestGraph {
28+
num_nodes: start_node + 1,
29+
start_node: start_node,
30+
successors: HashMap::new(),
31+
predecessors: HashMap::new()
32+
};
33+
for &(source, target) in edges {
34+
graph.num_nodes = max(graph.num_nodes, source + 1);
35+
graph.num_nodes = max(graph.num_nodes, target + 1);
36+
graph.successors.entry(source).or_insert(vec![]).push(target);
37+
graph.predecessors.entry(target).or_insert(vec![]).push(source);
38+
}
39+
for node in 0..graph.num_nodes {
40+
graph.successors.entry(node).or_insert(vec![]);
41+
graph.predecessors.entry(node).or_insert(vec![]);
42+
}
43+
graph
44+
}
45+
}
46+
47+
impl Graph for TestGraph {
48+
type Node = usize;
49+
50+
fn start_node(&self) -> usize {
51+
self.start_node
52+
}
53+
54+
fn num_nodes(&self) -> usize {
55+
self.num_nodes
56+
}
57+
58+
fn predecessors<'graph>(&'graph self, node: usize)
59+
-> <Self as GraphPredecessors<'graph>>::Iter {
60+
self.predecessors[&node].iter().cloned()
61+
}
62+
63+
fn successors<'graph>(&'graph self, node: usize)
64+
-> <Self as GraphSuccessors<'graph>>::Iter {
65+
self.successors[&node].iter().cloned()
66+
}
67+
}
68+
69+
impl<'graph> GraphPredecessors<'graph> for TestGraph {
70+
type Item = usize;
71+
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
72+
}
73+
74+
impl<'graph> GraphSuccessors<'graph> for TestGraph {
75+
type Item = usize;
76+
type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
77+
}
78+
79+
// impl NodeIndex for usize {
80+
// }
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
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+
use super::*;
12+
13+
pub struct TransposedGraph<G: Graph> {
14+
base_graph: G,
15+
start_node: G::Node,
16+
}
17+
18+
impl<G: Graph> TransposedGraph<G> {
19+
pub fn new(base_graph: G) -> Self {
20+
let start_node = base_graph.start_node();
21+
Self::with_start(base_graph, start_node)
22+
}
23+
24+
pub fn with_start(base_graph: G, start_node: G::Node) -> Self {
25+
TransposedGraph { base_graph: base_graph, start_node: start_node }
26+
}
27+
}
28+
29+
impl<G: Graph> Graph for TransposedGraph<G> {
30+
type Node = G::Node;
31+
32+
fn num_nodes(&self) -> usize {
33+
self.base_graph.num_nodes()
34+
}
35+
36+
fn start_node(&self) -> Self::Node {
37+
self.start_node
38+
}
39+
40+
fn predecessors<'graph>(&'graph self, node: Self::Node)
41+
-> <Self as GraphPredecessors<'graph>>::Iter {
42+
self.base_graph.successors(node)
43+
}
44+
45+
fn successors<'graph>(&'graph self, node: Self::Node)
46+
-> <Self as GraphSuccessors<'graph>>::Iter {
47+
self.base_graph.predecessors(node)
48+
}
49+
}
50+
51+
impl<'graph, G: Graph> GraphPredecessors<'graph> for TransposedGraph<G> {
52+
type Item = G::Node;
53+
type Iter = <G as GraphSuccessors<'graph>>::Iter;
54+
}
55+
56+
impl<'graph, G: Graph> GraphSuccessors<'graph> for TransposedGraph<G> {
57+
type Item = G::Node;
58+
type Iter = <G as GraphPredecessors<'graph>>::Iter;
59+
}

‎src/librustc_data_structures/indexed_vec.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::fmt::Debug;
1112
use std::iter::{self, FromIterator};
1213
use std::slice;
1314
use std::marker::PhantomData;
@@ -20,7 +21,7 @@ use rustc_serialize as serialize;
2021
/// Represents some newtyped `usize` wrapper.
2122
///
2223
/// (purpose: avoid mixing indexes for different bitvector domains.)
23-
pub trait Idx: Copy + 'static {
24+
pub trait Idx: Copy + 'static + Eq + Debug {
2425
fn new(usize) -> Self;
2526
fn index(self) -> usize;
2627
}
@@ -76,6 +77,13 @@ impl<I: Idx, T> IndexVec<I, T> {
7677
IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
7778
}
7879

80+
#[inline]
81+
pub fn from_elem_n(elem: T, n: usize) -> Self
82+
where T: Clone
83+
{
84+
IndexVec { raw: vec![elem; n], _marker: PhantomData }
85+
}
86+
7987
#[inline]
8088
pub fn push(&mut self, d: T) -> I {
8189
let idx = I::new(self.len());

‎src/librustc_data_structures/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ pub mod unify;
5050
pub mod fnv;
5151
pub mod tuple_slice;
5252
pub mod veccell;
53+
pub mod graph_algorithms;
5354

5455
// See comments in src/librustc/lib.rs
5556
#[doc(hidden)]

0 commit comments

Comments
 (0)
Please sign in to comment.