Skip to content

Commit a0f572e

Browse files
authoredJun 27, 2016
Auto merge of #34169 - scottcarr:dominator-cache, r=nikomatsakis
[MIR] Add Dominators to MIR and Add Graph Algorithms ~~This PR assumes PR #34149 lands.~~ Add generic graph algorithms to rustc_data_structures. Add dominators and successors to the ~~cache (that currently only holds predecessors).~~ `Mir`.
2 parents 126af08 + 66d60c7 commit a0f572e

File tree

14 files changed

+871
-3
lines changed

14 files changed

+871
-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

+40-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ 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::control_flow_graph::dominators::{Dominators, dominators};
16+
use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors};
17+
use rustc_data_structures::control_flow_graph::ControlFlowGraph;
1518
use hir::def_id::DefId;
1619
use ty::subst::Substs;
1720
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
@@ -24,6 +27,7 @@ use std::cell::Ref;
2427
use std::fmt::{self, Debug, Formatter, Write};
2528
use std::{iter, u32};
2629
use std::ops::{Index, IndexMut};
30+
use std::vec::IntoIter;
2731
use syntax::ast::{self, Name};
2832
use syntax::codemap::Span;
2933

@@ -54,7 +58,7 @@ macro_rules! newtype_index {
5458
}
5559

5660
/// Lowered representation of a single function.
57-
#[derive(Clone, RustcEncodable, RustcDecodable)]
61+
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
5862
pub struct Mir<'tcx> {
5963
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
6064
/// that indexes into this vector.
@@ -145,6 +149,11 @@ impl<'tcx> Mir<'tcx> {
145149
Ref::map(self.predecessors(), |p| &p[bb])
146150
}
147151

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

+9-1
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

+1
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 control_flow_graph;
5354

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

0 commit comments

Comments
 (0)
Please sign in to comment.