use rustc_serialize as serialize;
-#[derive(Clone)]
+#[derive(Clone, Debug)]
pub struct Cache {
predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
}
use middle::const_val::ConstVal;
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
+use rustc_data_structures::control_flow_graph::dominators::{Dominators, dominators};
+use rustc_data_structures::control_flow_graph::{GraphPredecessors, GraphSuccessors};
+use rustc_data_structures::control_flow_graph::ControlFlowGraph;
use hir::def_id::DefId;
use ty::subst::Substs;
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
use std::fmt::{self, Debug, Formatter, Write};
use std::{iter, u32};
use std::ops::{Index, IndexMut};
+use std::vec::IntoIter;
use syntax::ast::{self, Name};
use syntax::codemap::Span;
}
/// Lowered representation of a single function.
-#[derive(Clone, RustcEncodable, RustcDecodable)]
+#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct Mir<'tcx> {
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
/// that indexes into this vector.
Ref::map(self.predecessors(), |p| &p[bb])
}
+ #[inline]
+ pub fn dominators(&self) -> Dominators<BasicBlock> {
+ dominators(self)
+ }
+
/// Maps locals (Arg's, Var's, Temp's and ReturnPointer, in that order)
/// to their index in the whole list of locals. This is useful if you
/// want to treat all locals the same instead of repeating yourself.
fn item_path_str(def_id: DefId) -> String {
ty::tls::with(|tcx| tcx.item_path_str(def_id))
}
+
+impl<'tcx> ControlFlowGraph for Mir<'tcx> {
+
+ type Node = BasicBlock;
+
+ fn num_nodes(&self) -> usize { self.basic_blocks.len() }
+
+ fn start_node(&self) -> Self::Node { START_BLOCK }
+
+ fn predecessors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphPredecessors<'graph>>::Iter
+ {
+ self.predecessors_for(node).clone().into_iter()
+ }
+ fn successors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphSuccessors<'graph>>::Iter
+ {
+ self.basic_blocks[node].terminator().successors().into_owned().into_iter()
+ }
+}
+
+impl<'a, 'b> GraphPredecessors<'b> for Mir<'a> {
+ type Item = BasicBlock;
+ type Iter = IntoIter<BasicBlock>;
+}
+
+impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> {
+ type Item = BasicBlock;
+ type Iter = IntoIter<BasicBlock>;
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Algorithm citation:
+//! A Simple, Fast Dominance Algorithm.
+//! Keith D. Cooper, Timothy J. Harvey, and Ken Kennedy
+//! Rice Computer Science TS-06-33870
+//! https://www.cs.rice.edu/~keith/EMBED/dom.pdf
+
+use super::ControlFlowGraph;
+use super::iterate::reverse_post_order;
+use super::super::indexed_vec::{IndexVec, Idx};
+
+use std::fmt;
+
+#[cfg(test)]
+mod test;
+
+pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
+ let start_node = graph.start_node();
+ let rpo = reverse_post_order(graph, start_node);
+ dominators_given_rpo(graph, &rpo)
+}
+
+pub fn dominators_given_rpo<G: ControlFlowGraph>(graph: &G,
+ rpo: &[G::Node])
+ -> Dominators<G::Node> {
+ let start_node = graph.start_node();
+ assert_eq!(rpo[0], start_node);
+
+ // compute the post order index (rank) for each node
+ let mut post_order_rank: IndexVec<G::Node, usize> = IndexVec::from_elem_n(usize::default(),
+ graph.num_nodes());
+ for (index, node) in rpo.iter().rev().cloned().enumerate() {
+ post_order_rank[node] = index;
+ }
+
+ let mut immediate_dominators: IndexVec<G::Node, Option<G::Node>> =
+ IndexVec::from_elem_n(Option::default(), graph.num_nodes());
+ immediate_dominators[start_node] = Some(start_node);
+
+ let mut changed = true;
+ while changed {
+ changed = false;
+
+ for &node in &rpo[1..] {
+ let mut new_idom = None;
+ for pred in graph.predecessors(node) {
+ if immediate_dominators[pred].is_some() {
+ // (*)
+ // (*) dominators for `pred` have been calculated
+ new_idom = intersect_opt(&post_order_rank,
+ &immediate_dominators,
+ new_idom,
+ Some(pred));
+ }
+ }
+
+ if new_idom != immediate_dominators[node] {
+ immediate_dominators[node] = new_idom;
+ changed = true;
+ }
+ }
+ }
+
+ Dominators {
+ post_order_rank: post_order_rank,
+ immediate_dominators: immediate_dominators,
+ }
+}
+
+fn intersect_opt<Node: Idx>(post_order_rank: &IndexVec<Node, usize>,
+ immediate_dominators: &IndexVec<Node, Option<Node>>,
+ node1: Option<Node>,
+ node2: Option<Node>)
+ -> Option<Node> {
+ match (node1, node2) {
+ (None, None) => None,
+ (Some(n), None) | (None, Some(n)) => Some(n),
+ (Some(n1), Some(n2)) => Some(intersect(post_order_rank, immediate_dominators, n1, n2)),
+ }
+}
+
+fn intersect<Node: Idx>(post_order_rank: &IndexVec<Node, usize>,
+ immediate_dominators: &IndexVec<Node, Option<Node>>,
+ mut node1: Node,
+ mut node2: Node)
+ -> Node {
+ while node1 != node2 {
+ while post_order_rank[node1] < post_order_rank[node2] {
+ node1 = immediate_dominators[node1].unwrap();
+ }
+
+ while post_order_rank[node2] < post_order_rank[node1] {
+ node2 = immediate_dominators[node2].unwrap();
+ }
+ }
+ return node1;
+}
+
+#[derive(Clone, Debug)]
+pub struct Dominators<N: Idx> {
+ post_order_rank: IndexVec<N, usize>,
+ immediate_dominators: IndexVec<N, Option<N>>,
+}
+
+impl<Node: Idx> Dominators<Node> {
+ pub fn is_reachable(&self, node: Node) -> bool {
+ self.immediate_dominators[node].is_some()
+ }
+
+ pub fn immediate_dominator(&self, node: Node) -> Node {
+ assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+ self.immediate_dominators[node].unwrap()
+ }
+
+ pub fn dominators(&self, node: Node) -> Iter<Node> {
+ assert!(self.is_reachable(node), "node {:?} is not reachable", node);
+ Iter {
+ dominators: self,
+ node: Some(node),
+ }
+ }
+
+ pub fn is_dominated_by(&self, node: Node, dom: Node) -> bool {
+ // FIXME -- could be optimized by using post-order-rank
+ self.dominators(node).any(|n| n == dom)
+ }
+
+ pub fn mutual_dominator_node(&self, node1: Node, node2: Node) -> Node {
+ assert!(self.is_reachable(node1),
+ "node {:?} is not reachable",
+ node1);
+ assert!(self.is_reachable(node2),
+ "node {:?} is not reachable",
+ node2);
+ intersect::<Node>(&self.post_order_rank,
+ &self.immediate_dominators,
+ node1,
+ node2)
+ }
+
+ pub fn mutual_dominator<I>(&self, iter: I) -> Option<Node>
+ where I: IntoIterator<Item = Node>
+ {
+ let mut iter = iter.into_iter();
+ iter.next()
+ .map(|dom| iter.fold(dom, |dom, node| self.mutual_dominator_node(dom, node)))
+ }
+
+ pub fn all_immediate_dominators(&self) -> &IndexVec<Node, Option<Node>> {
+ &self.immediate_dominators
+ }
+
+ pub fn dominator_tree(&self) -> DominatorTree<Node> {
+ let elem: Vec<Node> = Vec::new();
+ let mut children: IndexVec<Node, Vec<Node>> =
+ IndexVec::from_elem_n(elem, self.immediate_dominators.len());
+ let mut root = None;
+ for (index, immed_dom) in self.immediate_dominators.iter().enumerate() {
+ let node = Node::new(index);
+ match *immed_dom {
+ None => {
+ // node not reachable
+ }
+ Some(immed_dom) => {
+ if node == immed_dom {
+ root = Some(node);
+ } else {
+ children[immed_dom].push(node);
+ }
+ }
+ }
+ }
+ DominatorTree {
+ root: root.unwrap(),
+ children: children,
+ }
+ }
+}
+
+pub struct Iter<'dom, Node: Idx + 'dom> {
+ dominators: &'dom Dominators<Node>,
+ node: Option<Node>,
+}
+
+impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
+ type Item = Node;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ if let Some(node) = self.node {
+ let dom = self.dominators.immediate_dominator(node);
+ if dom == node {
+ self.node = None; // reached the root
+ } else {
+ self.node = Some(dom);
+ }
+ return Some(node);
+ } else {
+ return None;
+ }
+ }
+}
+
+pub struct DominatorTree<N: Idx> {
+ root: N,
+ children: IndexVec<N, Vec<N>>,
+}
+
+impl<Node: Idx> DominatorTree<Node> {
+ pub fn root(&self) -> Node {
+ self.root
+ }
+
+ pub fn children(&self, node: Node) -> &[Node] {
+ &self.children[node]
+ }
+
+ pub fn iter_children_of(&self, node: Node) -> IterChildrenOf<Node> {
+ IterChildrenOf {
+ tree: self,
+ stack: vec![node],
+ }
+ }
+}
+
+pub struct IterChildrenOf<'iter, Node: Idx + 'iter> {
+ tree: &'iter DominatorTree<Node>,
+ stack: Vec<Node>,
+}
+
+impl<'iter, Node: Idx> Iterator for IterChildrenOf<'iter, Node> {
+ type Item = Node;
+
+ fn next(&mut self) -> Option<Node> {
+ if let Some(node) = self.stack.pop() {
+ self.stack.extend(self.tree.children(node));
+ Some(node)
+ } else {
+ None
+ }
+ }
+}
+
+impl<Node: Idx> fmt::Debug for DominatorTree<Node> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ fmt::Debug::fmt(&DominatorTreeNode {
+ tree: self,
+ node: self.root,
+ },
+ fmt)
+ }
+}
+
+struct DominatorTreeNode<'tree, Node: Idx> {
+ tree: &'tree DominatorTree<Node>,
+ node: Node,
+}
+
+impl<'tree, Node: Idx> fmt::Debug for DominatorTreeNode<'tree, Node> {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+ let subtrees: Vec<_> = self.tree
+ .children(self.node)
+ .iter()
+ .map(|&child| {
+ DominatorTreeNode {
+ tree: self.tree,
+ node: child,
+ }
+ })
+ .collect();
+ fmt.debug_tuple("")
+ .field(&self.node)
+ .field(&subtrees)
+ .finish()
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::super::test::TestGraph;
+
+use super::*;
+
+#[test]
+fn diamond() {
+ let graph = TestGraph::new(0, &[
+ (0, 1),
+ (0, 2),
+ (1, 3),
+ (2, 3),
+ ]);
+
+ let dominators = dominators(&graph);
+ let immediate_dominators = dominators.all_immediate_dominators();
+ assert_eq!(immediate_dominators[0], Some(0));
+ assert_eq!(immediate_dominators[1], Some(0));
+ assert_eq!(immediate_dominators[2], Some(0));
+ assert_eq!(immediate_dominators[3], Some(0));
+}
+
+#[test]
+fn paper() {
+ // example from the paper:
+ let graph = TestGraph::new(6, &[
+ (6, 5),
+ (6, 4),
+ (5, 1),
+ (4, 2),
+ (4, 3),
+ (1, 2),
+ (2, 3),
+ (3, 2),
+ (2, 1),
+ ]);
+
+ let dominators = dominators(&graph);
+ let immediate_dominators = dominators.all_immediate_dominators();
+ assert_eq!(immediate_dominators[0], None); // <-- note that 0 is not in graph
+ assert_eq!(immediate_dominators[1], Some(6));
+ assert_eq!(immediate_dominators[2], Some(6));
+ assert_eq!(immediate_dominators[3], Some(6));
+ assert_eq!(immediate_dominators[4], Some(6));
+ assert_eq!(immediate_dominators[5], Some(6));
+ assert_eq!(immediate_dominators[6], Some(6));
+}
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::ControlFlowGraph;
+use super::super::indexed_vec::IndexVec;
+
+#[cfg(test)]
+mod test;
+
+pub fn post_order_from<G: ControlFlowGraph>(graph: &G, start_node: G::Node) -> Vec<G::Node> {
+ post_order_from_to(graph, start_node, None)
+}
+
+pub fn post_order_from_to<G: ControlFlowGraph>(graph: &G,
+ start_node: G::Node,
+ end_node: Option<G::Node>)
+ -> Vec<G::Node> {
+ let mut visited: IndexVec<G::Node, bool> = IndexVec::from_elem_n(false, graph.num_nodes());
+ let mut result: Vec<G::Node> = Vec::with_capacity(graph.num_nodes());
+ if let Some(end_node) = end_node {
+ visited[end_node] = true;
+ }
+ post_order_walk(graph, start_node, &mut result, &mut visited);
+ result
+}
+
+fn post_order_walk<G: ControlFlowGraph>(graph: &G,
+ node: G::Node,
+ result: &mut Vec<G::Node>,
+ visited: &mut IndexVec<G::Node, bool>) {
+ if visited[node] {
+ return;
+ }
+ visited[node] = true;
+
+ for successor in graph.successors(node) {
+ post_order_walk(graph, successor, result, visited);
+ }
+
+ result.push(node);
+}
+
+pub fn pre_order_walk<G: ControlFlowGraph>(graph: &G,
+ node: G::Node,
+ result: &mut Vec<G::Node>,
+ visited: &mut IndexVec<G::Node, bool>) {
+ if visited[node] {
+ return;
+ }
+ visited[node] = true;
+
+ result.push(node);
+
+ for successor in graph.successors(node) {
+ pre_order_walk(graph, successor, result, visited);
+ }
+}
+
+pub fn reverse_post_order<G: ControlFlowGraph>(graph: &G, start_node: G::Node) -> Vec<G::Node> {
+ let mut vec = post_order_from(graph, start_node);
+ vec.reverse();
+ vec
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::super::test::TestGraph;
+use super::super::transpose::TransposedGraph;
+
+use super::*;
+
+#[test]
+fn diamond_post_order() {
+ let graph = TestGraph::new(0, &[
+ (0, 1),
+ (0, 2),
+ (1, 3),
+ (2, 3),
+ ]);
+
+ let result = post_order_from(&graph, 0);
+ assert_eq!(result, vec![3, 1, 2, 0]);
+}
+
+
+#[test]
+fn rev_post_order_inner_loop() {
+ // 0 -> 1 -> 2 -> 3 -> 5
+ // ^ ^ v |
+ // | 6 <- 4 |
+ // +-----------------+
+ let graph = TestGraph::new(0, &[
+ (0, 1),
+ (1, 2),
+ (2, 3),
+ (3, 5),
+ (3, 1),
+ (2, 4),
+ (4, 6),
+ (6, 2),
+ ]);
+
+ let rev_graph = TransposedGraph::new(&graph);
+
+ let result = post_order_from_to(&rev_graph, 6, Some(2));
+ assert_eq!(result, vec![4, 6]);
+
+ let result = post_order_from_to(&rev_graph, 3, Some(1));
+ assert_eq!(result, vec![4, 6, 2, 3]);
+}
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::indexed_vec::Idx;
+pub use std::slice::Iter;
+
+pub mod dominators;
+pub mod iterate;
+pub mod reachable;
+mod reference;
+pub mod transpose;
+
+#[cfg(test)]
+mod test;
+
+pub trait ControlFlowGraph
+ where Self: for<'graph> GraphPredecessors<'graph, Item=<Self as ControlFlowGraph>::Node>,
+ Self: for<'graph> GraphSuccessors<'graph, Item=<Self as ControlFlowGraph>::Node>
+{
+ type Node: Idx;
+
+ fn num_nodes(&self) -> usize;
+ fn start_node(&self) -> Self::Node;
+ fn predecessors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphPredecessors<'graph>>::Iter;
+ fn successors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphSuccessors<'graph>>::Iter;
+}
+
+pub trait GraphPredecessors<'graph> {
+ type Item;
+ type Iter: Iterator<Item=Self::Item>;
+}
+
+pub trait GraphSuccessors<'graph> {
+ type Item;
+ type Iter: Iterator<Item=Self::Item>;
+}
\ No newline at end of file
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Compute reachability using a simple dataflow propagation.
+//! Store end-result in a big NxN bit matrix.
+
+use super::ControlFlowGraph;
+use super::super::bitvec::BitVector;
+use super::iterate::reverse_post_order;
+use super::super::indexed_vec::{IndexVec, Idx};
+
+#[cfg(test)]
+mod test;
+
+pub fn reachable<G: ControlFlowGraph>(graph: &G)
+ -> Reachability<G::Node> {
+ let reverse_post_order = reverse_post_order(graph, graph.start_node());
+ reachable_given_rpo(graph, &reverse_post_order)
+}
+
+pub fn reachable_given_rpo<G: ControlFlowGraph>(graph: &G,
+ reverse_post_order: &[G::Node])
+ -> Reachability<G::Node> {
+ let mut reachability = Reachability::new(graph);
+ let mut changed = true;
+ while changed {
+ changed = false;
+ for &node in reverse_post_order.iter().rev() {
+ // every node can reach itself
+ changed |= reachability.bits[node].insert(node.index());
+
+ // and every pred can reach everything node can reach
+ for pred in graph.predecessors(node) {
+ let nodes_bits = reachability.bits[node].clone();
+ changed |= reachability.bits[pred].insert_all(&nodes_bits);
+ }
+ }
+ }
+ reachability
+}
+
+pub struct Reachability<Node: Idx> {
+ bits: IndexVec<Node, BitVector>,
+}
+
+impl<Node: Idx> Reachability<Node> {
+ fn new<G: ControlFlowGraph>(graph: &G) -> Self {
+ let num_nodes = graph.num_nodes();
+ Reachability {
+ bits: IndexVec::from_elem_n(BitVector::new(num_nodes), num_nodes),
+ }
+ }
+
+ pub fn can_reach(&self, source: Node, target: Node)-> bool {
+ let bit: usize = target.index();
+ self.bits[source].contains(bit)
+ }
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::super::test::TestGraph;
+
+use super::*;
+
+#[test]
+fn test1() {
+ // 0 -> 1 -> 2 -> 3
+ // ^ v
+ // 6 <- 4 -> 5
+ let graph = TestGraph::new(0, &[
+ (0, 1),
+ (1, 2),
+ (2, 3),
+ (2, 4),
+ (4, 5),
+ (4, 6),
+ (6, 1),
+ ]);
+ let reachable = reachable(&graph);
+ assert!((0..6).all(|i| reachable.can_reach(0, i)));
+ assert!((1..6).all(|i| reachable.can_reach(1, i)));
+ assert!((1..6).all(|i| reachable.can_reach(2, i)));
+ assert!((1..6).all(|i| reachable.can_reach(4, i)));
+ assert!((1..6).all(|i| reachable.can_reach(6, i)));
+ assert!(reachable.can_reach(3, 3));
+ assert!(!reachable.can_reach(3, 5));
+ assert!(!reachable.can_reach(5, 3));
+}
+
+/// use bigger indices to cross between words in the bit set
+#[test]
+fn test2() {
+ // 30 -> 31 -> 32 -> 33
+ // ^ v
+ // 36 <- 34 -> 35
+ let graph = TestGraph::new(30, &[
+ (30, 31),
+ (31, 32),
+ (32, 33),
+ (32, 34),
+ (34, 35),
+ (34, 36),
+ (36, 31),
+ ]);
+ let reachable = reachable(&graph);
+ assert!((30..36).all(|i| reachable.can_reach(30, i)));
+ assert!((31..36).all(|i| reachable.can_reach(31, i)));
+ assert!((31..36).all(|i| reachable.can_reach(32, i)));
+ assert!((31..36).all(|i| reachable.can_reach(34, i)));
+ assert!((31..36).all(|i| reachable.can_reach(36, i)));
+ assert!(reachable.can_reach(33, 33));
+ assert!(!reachable.can_reach(33, 35));
+ assert!(!reachable.can_reach(35, 33));
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+
+impl<'graph, G: ControlFlowGraph> ControlFlowGraph for &'graph G {
+ type Node = G::Node;
+
+ fn num_nodes(&self) -> usize {
+ (**self).num_nodes()
+ }
+
+ fn start_node(&self) -> Self::Node {
+ (**self).start_node()
+ }
+
+ fn predecessors<'iter>(&'iter self, node: Self::Node)
+ -> <Self as GraphPredecessors<'iter>>::Iter {
+ (**self).predecessors(node)
+ }
+
+ fn successors<'iter>(&'iter self, node: Self::Node)
+ -> <Self as GraphSuccessors<'iter>>::Iter {
+ (**self).successors(node)
+ }
+}
+
+impl<'iter, 'graph, G: ControlFlowGraph> GraphPredecessors<'iter> for &'graph G {
+ type Item = G::Node;
+ type Iter = <G as GraphPredecessors<'iter>>::Iter;
+}
+
+impl<'iter, 'graph, G: ControlFlowGraph> GraphSuccessors<'iter> for &'graph G {
+ type Item = G::Node;
+ type Iter = <G as GraphSuccessors<'iter>>::Iter;
+}
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::collections::HashMap;
+use std::cmp::max;
+use std::slice;
+use std::iter;
+
+use super::{ControlFlowGraph, GraphPredecessors, GraphSuccessors};
+
+pub struct TestGraph {
+ num_nodes: usize,
+ start_node: usize,
+ successors: HashMap<usize, Vec<usize>>,
+ predecessors: HashMap<usize, Vec<usize>>,
+}
+
+impl TestGraph {
+ pub fn new(start_node: usize, edges: &[(usize, usize)]) -> Self {
+ let mut graph = TestGraph {
+ num_nodes: start_node + 1,
+ start_node: start_node,
+ successors: HashMap::new(),
+ predecessors: HashMap::new()
+ };
+ for &(source, target) in edges {
+ graph.num_nodes = max(graph.num_nodes, source + 1);
+ graph.num_nodes = max(graph.num_nodes, target + 1);
+ graph.successors.entry(source).or_insert(vec![]).push(target);
+ graph.predecessors.entry(target).or_insert(vec![]).push(source);
+ }
+ for node in 0..graph.num_nodes {
+ graph.successors.entry(node).or_insert(vec![]);
+ graph.predecessors.entry(node).or_insert(vec![]);
+ }
+ graph
+ }
+}
+
+impl ControlFlowGraph for TestGraph {
+ type Node = usize;
+
+ fn start_node(&self) -> usize {
+ self.start_node
+ }
+
+ fn num_nodes(&self) -> usize {
+ self.num_nodes
+ }
+
+ fn predecessors<'graph>(&'graph self, node: usize)
+ -> <Self as GraphPredecessors<'graph>>::Iter {
+ self.predecessors[&node].iter().cloned()
+ }
+
+ fn successors<'graph>(&'graph self, node: usize)
+ -> <Self as GraphSuccessors<'graph>>::Iter {
+ self.successors[&node].iter().cloned()
+ }
+}
+
+impl<'graph> GraphPredecessors<'graph> for TestGraph {
+ type Item = usize;
+ type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
+}
+
+impl<'graph> GraphSuccessors<'graph> for TestGraph {
+ type Item = usize;
+ type Iter = iter::Cloned<slice::Iter<'graph, usize>>;
+}
+
--- /dev/null
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use super::*;
+
+pub struct TransposedGraph<G: ControlFlowGraph> {
+ base_graph: G,
+ start_node: G::Node,
+}
+
+impl<G: ControlFlowGraph> TransposedGraph<G> {
+ pub fn new(base_graph: G) -> Self {
+ let start_node = base_graph.start_node();
+ Self::with_start(base_graph, start_node)
+ }
+
+ pub fn with_start(base_graph: G, start_node: G::Node) -> Self {
+ TransposedGraph { base_graph: base_graph, start_node: start_node }
+ }
+}
+
+impl<G: ControlFlowGraph> ControlFlowGraph for TransposedGraph<G> {
+ type Node = G::Node;
+
+ fn num_nodes(&self) -> usize {
+ self.base_graph.num_nodes()
+ }
+
+ fn start_node(&self) -> Self::Node {
+ self.start_node
+ }
+
+ fn predecessors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphPredecessors<'graph>>::Iter {
+ self.base_graph.successors(node)
+ }
+
+ fn successors<'graph>(&'graph self, node: Self::Node)
+ -> <Self as GraphSuccessors<'graph>>::Iter {
+ self.base_graph.predecessors(node)
+ }
+}
+
+impl<'graph, G: ControlFlowGraph> GraphPredecessors<'graph> for TransposedGraph<G> {
+ type Item = G::Node;
+ type Iter = <G as GraphSuccessors<'graph>>::Iter;
+}
+
+impl<'graph, G: ControlFlowGraph> GraphSuccessors<'graph> for TransposedGraph<G> {
+ type Item = G::Node;
+ type Iter = <G as GraphPredecessors<'graph>>::Iter;
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+use std::fmt::Debug;
use std::iter::{self, FromIterator};
use std::slice;
use std::marker::PhantomData;
/// Represents some newtyped `usize` wrapper.
///
/// (purpose: avoid mixing indexes for different bitvector domains.)
-pub trait Idx: Copy + 'static {
+pub trait Idx: Copy + 'static + Eq + Debug {
fn new(usize) -> Self;
fn index(self) -> usize;
}
IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
}
+ #[inline]
+ pub fn from_elem_n(elem: T, n: usize) -> Self
+ where T: Clone
+ {
+ IndexVec { raw: vec![elem; n], _marker: PhantomData }
+ }
+
#[inline]
pub fn push(&mut self, d: T) -> I {
let idx = I::new(self.len());
pub mod fnv;
pub mod tuple_slice;
pub mod veccell;
+pub mod control_flow_graph;
// See comments in src/librustc/lib.rs
#[doc(hidden)]