diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 138fed2d64e23..1be7d00f072cd 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -15,7 +15,7 @@ use mir::repr::{Mir, BasicBlock}; use rustc_serialize as serialize; -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Cache { predecessors: RefCell>>> } diff --git a/src/librustc/mir/repr.rs b/src/librustc/mir/repr.rs index 03ae91fefb925..51ded877f94a2 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -12,6 +12,8 @@ use graphviz::IntoCow; use middle::const_val::ConstVal; use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr}; use rustc_data_structures::indexed_vec::{IndexVec, Idx}; +use rustc_data_structures::graph_algorithms::dominators::{Dominators, dominators}; +use rustc_data_structures::graph_algorithms::{Graph, GraphPredecessors, GraphSuccessors}; use hir::def_id::DefId; use ty::subst::Substs; use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty}; @@ -24,6 +26,7 @@ use std::cell::Ref; 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; @@ -54,7 +57,7 @@ macro_rules! newtype_index { } /// 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. @@ -144,6 +147,13 @@ impl<'tcx> Mir<'tcx> { pub fn predecessors_for(&self, bb: BasicBlock) -> Ref> { Ref::map(self.predecessors(), |p| &p[bb]) } + + #[inline] + //pub fn dominators(&'tcx self) -> Ref> { + pub fn dominators(&self) -> Dominators { + //self.cache.dominators(self) + dominators(self) + } } impl<'tcx> Index for Mir<'tcx> { @@ -162,6 +172,18 @@ impl<'tcx> IndexMut for Mir<'tcx> { } } +impl From for BasicBlock { + fn from(n: usize) -> BasicBlock { + assert!(n < (u32::MAX as usize)); + BasicBlock(n as u32) + } +} +impl Into for BasicBlock { + fn into(self: BasicBlock) -> usize { + self.index() + } +} + /// Grouped information about the source code origin of a MIR entity. /// Intended to be inspected by diagnostics and debuginfo. /// Most passes can work with it as a whole, within a single function. @@ -1155,3 +1177,33 @@ fn node_to_string(node_id: ast::NodeId) -> String { fn item_path_str(def_id: DefId) -> String { ty::tls::with(|tcx| tcx.item_path_str(def_id)) } + +impl<'tcx> Graph 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) + -> >::Iter + { + self.predecessors_for(node).clone().into_iter() + } + fn successors<'graph>(&'graph self, node: Self::Node) + -> >::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; +} + +impl<'a, 'b> GraphSuccessors<'b> for Mir<'a> { + type Item = BasicBlock; + type Iter = IntoIter; +} diff --git a/src/librustc_data_structures/graph_algorithms/dominators/mod.rs b/src/librustc_data_structures/graph_algorithms/dominators/mod.rs new file mode 100644 index 0000000000000..7eaf7188f0dd1 --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/dominators/mod.rs @@ -0,0 +1,282 @@ +// 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 or the MIT license +// , 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::Graph; +use super::iterate::reverse_post_order; +use super::super::indexed_vec::{IndexVec, Idx}; + +use std::fmt; + +#[cfg(test)] +mod test; + +pub fn dominators(graph: &G) -> Dominators { + let start_node = graph.start_node(); + let rpo = reverse_post_order(graph, start_node); + dominators_given_rpo(graph, &rpo) +} + +pub fn dominators_given_rpo(graph: &G, rpo: &[G::Node]) -> Dominators { + 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 = 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> = + 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(post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + node1: Option, + node2: Option) + -> Option { + 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(post_order_rank: &IndexVec, + immediate_dominators: &IndexVec>, + mut node1: G::Node, + mut node2: G::Node) + -> G::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 { + post_order_rank: IndexVec, + immediate_dominators: IndexVec>, +} + +impl Dominators { + pub fn is_reachable(&self, node: G::Node) -> bool { + self.immediate_dominators[node].is_some() + } + + pub fn immediate_dominator(&self, node: G::Node) -> G::Node { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + self.immediate_dominators[node].unwrap() + } + + pub fn dominators(&self, node: G::Node) -> Iter { + assert!(self.is_reachable(node), "node {:?} is not reachable", node); + Iter { + dominators: self, + node: Some(node), + } + } + + pub fn is_dominated_by(&self, node: G::Node, dom: G::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: G::Node, node2: G::Node) -> G::Node { + assert!(self.is_reachable(node1), + "node {:?} is not reachable", + node1); + assert!(self.is_reachable(node2), + "node {:?} is not reachable", + node2); + intersect::(&self.post_order_rank, + &self.immediate_dominators, + node1, + node2) + } + + pub fn mutual_dominator(&self, iter: I) -> Option + where I: IntoIterator + { + 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> { + &self.immediate_dominators + } + + pub fn dominator_tree(&self) -> DominatorTree { + let elem: Vec = Vec::new(); + let mut children: IndexVec> = + 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 = G::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, G: Graph + 'dom> { + dominators: &'dom Dominators, + node: Option, +} + +impl<'dom, G: Graph> Iterator for Iter<'dom, G> { + type Item = G::Node; + + fn next(&mut self) -> Option { + 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 { + root: G::Node, + children: IndexVec>, +} + +impl DominatorTree { + pub fn root(&self) -> G::Node { + self.root + } + + pub fn children(&self, node: G::Node) -> &[G::Node] { + &self.children[node] + } + + pub fn iter_children_of(&self, node: G::Node) -> IterChildrenOf { + IterChildrenOf { + tree: self, + stack: vec![node], + } + } +} + +pub struct IterChildrenOf<'iter, G: Graph + 'iter> { + tree: &'iter DominatorTree, + stack: Vec, +} + +impl<'iter, G: Graph> Iterator for IterChildrenOf<'iter, G> { + type Item = G::Node; + + fn next(&mut self) -> Option { + if let Some(node) = self.stack.pop() { + self.stack.extend(self.tree.children(node)); + Some(node) + } else { + None + } + } +} + +impl fmt::Debug for DominatorTree { + fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { + fmt::Debug::fmt(&DominatorTreeNode { + tree: self, + node: self.root, + }, + fmt) + } +} + +struct DominatorTreeNode<'tree, G: Graph + 'tree> { + tree: &'tree DominatorTree, + node: G::Node, +} + +impl<'tree, G: Graph> fmt::Debug for DominatorTreeNode<'tree, G> { + 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() + } +} diff --git a/src/librustc_data_structures/graph_algorithms/dominators/test.rs b/src/librustc_data_structures/graph_algorithms/dominators/test.rs new file mode 100644 index 0000000000000..a53313b941bd4 --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/dominators/test.rs @@ -0,0 +1,53 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use test::TestGraph; + +use super::*; + +#[test] +fn diamond() { + let graph = TestGraph::new(0, &[ + (0, 1), + (0, 2), + (1, 3), + (2, 3), + ]); + + let dominators = dominators(&graph); + assert_eq!(&dominators.all_immediate_dominators().vec[..], + &[Some(0), + Some(0), + Some(0), + 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); + assert_eq!(&dominators.all_immediate_dominators().vec[..], + &[None, // <-- note that 0 is not in graph + Some(6), Some(6), Some(6), + Some(6), Some(6), Some(6)]); +} + diff --git a/src/librustc_data_structures/graph_algorithms/iterate/mod.rs b/src/librustc_data_structures/graph_algorithms/iterate/mod.rs new file mode 100644 index 0000000000000..885fcc8f26e5f --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/iterate/mod.rs @@ -0,0 +1,70 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::Graph; +use super::super::indexed_vec::IndexVec; + +#[cfg(test)] +mod test; + +pub fn post_order_from(graph: &G, start_node: G::Node) -> Vec { + post_order_from_to(graph, start_node, None) +} + +pub fn post_order_from_to(graph: &G, + start_node: G::Node, + end_node: Option) + -> Vec { + let mut visited: IndexVec = IndexVec::from_elem_n(false, graph.num_nodes()); + let mut result: Vec = 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(graph: &G, + node: G::Node, + result: &mut Vec, + visited: &mut IndexVec) { + 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(graph: &G, + node: G::Node, + result: &mut Vec, + visited: &mut IndexVec) { + 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(graph: &G, start_node: G::Node) -> Vec { + let mut vec = post_order_from(graph, start_node); + vec.reverse(); + vec +} diff --git a/src/librustc_data_structures/graph_algorithms/iterate/test.rs b/src/librustc_data_structures/graph_algorithms/iterate/test.rs new file mode 100644 index 0000000000000..38bb75924075e --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/iterate/test.rs @@ -0,0 +1,55 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use test::TestGraph; +use 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]); +} + diff --git a/src/librustc_data_structures/graph_algorithms/mod.rs b/src/librustc_data_structures/graph_algorithms/mod.rs new file mode 100644 index 0000000000000..fb70702ec34dd --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/mod.rs @@ -0,0 +1,45 @@ +// 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 or the MIT license +// , 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 Graph + where Self: for<'graph> GraphPredecessors<'graph, Item=::Node>, + Self: for<'graph> GraphSuccessors<'graph, Item=::Node> +{ + type Node: Idx; + + fn num_nodes(&self) -> usize; + fn start_node(&self) -> Self::Node; + fn predecessors<'graph>(&'graph self, node: Self::Node) + -> >::Iter; + fn successors<'graph>(&'graph self, node: Self::Node) + -> >::Iter; +} + +pub trait GraphPredecessors<'graph> { + type Item; + type Iter: Iterator; +} + +pub trait GraphSuccessors<'graph> { + type Item; + type Iter: Iterator; +} \ No newline at end of file diff --git a/src/librustc_data_structures/graph_algorithms/reachable/mod.rs b/src/librustc_data_structures/graph_algorithms/reachable/mod.rs new file mode 100644 index 0000000000000..f7a9e444a4044 --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/reachable/mod.rs @@ -0,0 +1,69 @@ +// 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 or the MIT license +// , 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::Graph; +use super::super::bitvec::BitVector; +use super::iterate::reverse_post_order; +use super::super::indexed_vec::Idx; + +#[cfg(test)] +mod test; + +pub fn reachable(graph: &G) + -> Reachability { + let reverse_post_order = reverse_post_order(graph, graph.start_node()); + reachable_given_rpo(graph, &reverse_post_order) +} + +pub fn reachable_given_rpo(graph: &G, + reverse_post_order: &[G::Node]) + -> Reachability { + 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.insert(node, node.as_usize()); + changed |= reachability.bits[node.index()].insert(node.index()); + + // and every pred can reach everything node can reach + for pred in graph.predecessors(node) { + //changed |= reachability.bits.insert_bits_from(node, pred); + changed |= reachability.bits[node.index()].insert(pred.index()); + } + } + } + reachability +} + +//pub struct Reachability { +pub struct Reachability { + //bits: BitSet, + bits: Vec, +} + +//impl Reachability { +impl Reachability { + fn new(graph: &G) -> Self { + let num_nodes = graph.num_nodes(); + Reachability { + bits: vec![BitVector::new(num_nodes)], + } + } + + pub fn can_reach(&self, source: G::Node, target: G::Node) -> bool { + let bit: usize = target.index(); + self.bits[source.index()].contains(bit) + } +} diff --git a/src/librustc_data_structures/graph_algorithms/reachable/test.rs b/src/librustc_data_structures/graph_algorithms/reachable/test.rs new file mode 100644 index 0000000000000..64384e644a927 --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/reachable/test.rs @@ -0,0 +1,64 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use 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)); +} diff --git a/src/librustc_data_structures/graph_algorithms/reference.rs b/src/librustc_data_structures/graph_algorithms/reference.rs new file mode 100644 index 0000000000000..0f72138281d6f --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/reference.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::*; + +impl<'graph, G: Graph> Graph 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) + -> >::Iter { + (**self).predecessors(node) + } + + fn successors<'iter>(&'iter self, node: Self::Node) + -> >::Iter { + (**self).successors(node) + } +} + +impl<'iter, 'graph, G: Graph> GraphPredecessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'iter, 'graph, G: Graph> GraphSuccessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} diff --git a/src/librustc_data_structures/graph_algorithms/test.rs b/src/librustc_data_structures/graph_algorithms/test.rs new file mode 100644 index 0000000000000..e28b8a0d5b940 --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/test.rs @@ -0,0 +1,80 @@ +// 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 or the MIT license +// , 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::{Graph, GraphPredecessors, GraphSuccessors, NodeIndex}; + +pub struct TestGraph { + num_nodes: usize, + start_node: usize, + successors: HashMap>, + predecessors: HashMap>, +} + +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 Graph 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) + -> >::Iter { + self.predecessors[&node].iter().cloned() + } + + fn successors<'graph>(&'graph self, node: usize) + -> >::Iter { + self.successors[&node].iter().cloned() + } +} + +impl<'graph> GraphPredecessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} + +impl<'graph> GraphSuccessors<'graph> for TestGraph { + type Item = usize; + type Iter = iter::Cloned>; +} + +impl NodeIndex for usize { +} diff --git a/src/librustc_data_structures/graph_algorithms/transpose.rs b/src/librustc_data_structures/graph_algorithms/transpose.rs new file mode 100644 index 0000000000000..d341c51d704bf --- /dev/null +++ b/src/librustc_data_structures/graph_algorithms/transpose.rs @@ -0,0 +1,59 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use super::*; + +pub struct TransposedGraph { + base_graph: G, + start_node: G::Node, +} + +impl TransposedGraph { + 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 Graph for TransposedGraph { + 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) + -> >::Iter { + self.base_graph.successors(node) + } + + fn successors<'graph>(&'graph self, node: Self::Node) + -> >::Iter { + self.base_graph.predecessors(node) + } +} + +impl<'graph, G: Graph> GraphPredecessors<'graph> for TransposedGraph { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'graph, G: Graph> GraphSuccessors<'graph> for TransposedGraph { + type Item = G::Node; + type Iter = >::Iter; +} diff --git a/src/librustc_data_structures/indexed_vec.rs b/src/librustc_data_structures/indexed_vec.rs index db054477f75a1..b3918f1e4bc8b 100644 --- a/src/librustc_data_structures/indexed_vec.rs +++ b/src/librustc_data_structures/indexed_vec.rs @@ -8,6 +8,7 @@ // 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; @@ -20,7 +21,7 @@ use rustc_serialize as serialize; /// 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; } @@ -76,6 +77,13 @@ impl IndexVec { 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()); diff --git a/src/librustc_data_structures/lib.rs b/src/librustc_data_structures/lib.rs index 9370ad016ef1e..f7bcc2478694a 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -50,6 +50,7 @@ pub mod unify; pub mod fnv; pub mod tuple_slice; pub mod veccell; +pub mod graph_algorithms; // See comments in src/librustc/lib.rs #[doc(hidden)]