diff --git a/src/librustc/mir/cache.rs b/src/librustc/mir/cache.rs index 138fed2d64e..1be7d00f072 100644 --- a/src/librustc/mir/cache.rs +++ b/src/librustc/mir/cache.rs @@ -15,7 +15,7 @@ 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 a6052f9aa75..d39ff288418 100644 --- a/src/librustc/mir/repr.rs +++ b/src/librustc/mir/repr.rs @@ -12,6 +12,9 @@ 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}; @@ -24,6 +27,7 @@ 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 +58,7 @@ fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { } /// 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. @@ -145,6 +149,11 @@ pub fn predecessors_for(&self, bb: BasicBlock) -> Ref> { Ref::map(self.predecessors(), |p| &p[bb]) } + #[inline] + pub fn dominators(&self) -> Dominators { + 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. @@ -1190,3 +1199,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> 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) + -> >::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/control_flow_graph/dominators/mod.rs b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs new file mode 100644 index 00000000000..250b89d12ed --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/dominators/mod.rs @@ -0,0 +1,284 @@ +// 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::ControlFlowGraph; +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: 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 { + post_order_rank: IndexVec, + immediate_dominators: IndexVec>, +} + +impl Dominators { + 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 { + 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::(&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 = 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: Option, +} + +impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { + type Item = 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: N, + children: IndexVec>, +} + +impl DominatorTree { + 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 { + IterChildrenOf { + tree: self, + stack: vec![node], + } + } +} + +pub struct IterChildrenOf<'iter, Node: Idx + 'iter> { + tree: &'iter DominatorTree, + stack: Vec, +} + +impl<'iter, Node: Idx> Iterator for IterChildrenOf<'iter, Node> { + type Item = 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, Node: Idx> { + tree: &'tree DominatorTree, + 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() + } +} diff --git a/src/librustc_data_structures/control_flow_graph/dominators/test.rs b/src/librustc_data_structures/control_flow_graph/dominators/test.rs new file mode 100644 index 00000000000..a6db5f2fe3e --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/dominators/test.rs @@ -0,0 +1,57 @@ +// 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::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)); +} + diff --git a/src/librustc_data_structures/control_flow_graph/iterate/mod.rs b/src/librustc_data_structures/control_flow_graph/iterate/mod.rs new file mode 100644 index 00000000000..11b557cbcad --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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::ControlFlowGraph; +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/control_flow_graph/iterate/test.rs b/src/librustc_data_structures/control_flow_graph/iterate/test.rs new file mode 100644 index 00000000000..28297d55bdf --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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 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]); +} + diff --git a/src/librustc_data_structures/control_flow_graph/mod.rs b/src/librustc_data_structures/control_flow_graph/mod.rs new file mode 100644 index 00000000000..f9e75b12e03 --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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 ControlFlowGraph + 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/control_flow_graph/reachable/mod.rs b/src/librustc_data_structures/control_flow_graph/reachable/mod.rs new file mode 100644 index 00000000000..e520e23f3af --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/reachable/mod.rs @@ -0,0 +1,65 @@ +// 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::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(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[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 { + bits: IndexVec, +} + +impl Reachability { + fn new(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) + } +} diff --git a/src/librustc_data_structures/control_flow_graph/reachable/test.rs b/src/librustc_data_structures/control_flow_graph/reachable/test.rs new file mode 100644 index 00000000000..6aa906a0804 --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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 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)); +} diff --git a/src/librustc_data_structures/control_flow_graph/reference.rs b/src/librustc_data_structures/control_flow_graph/reference.rs new file mode 100644 index 00000000000..d735be1ed2f --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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: 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) + -> >::Iter { + (**self).predecessors(node) + } + + fn successors<'iter>(&'iter self, node: Self::Node) + -> >::Iter { + (**self).successors(node) + } +} + +impl<'iter, 'graph, G: ControlFlowGraph> GraphPredecessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'iter, 'graph, G: ControlFlowGraph> GraphSuccessors<'iter> for &'graph G { + type Item = G::Node; + type Iter = >::Iter; +} diff --git a/src/librustc_data_structures/control_flow_graph/test.rs b/src/librustc_data_structures/control_flow_graph/test.rs new file mode 100644 index 00000000000..57b2a858de5 --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/test.rs @@ -0,0 +1,78 @@ +// 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::{ControlFlowGraph, GraphPredecessors, GraphSuccessors}; + +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 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) + -> >::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>; +} + diff --git a/src/librustc_data_structures/control_flow_graph/transpose.rs b/src/librustc_data_structures/control_flow_graph/transpose.rs new file mode 100644 index 00000000000..792e079c28c --- /dev/null +++ b/src/librustc_data_structures/control_flow_graph/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 ControlFlowGraph 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: ControlFlowGraph> GraphPredecessors<'graph> for TransposedGraph { + type Item = G::Node; + type Iter = >::Iter; +} + +impl<'graph, G: ControlFlowGraph> 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 db054477f75..b3918f1e4bc 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 @@ /// 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 @@ pub fn from_elem(elem: T, universe: &IndexVec) -> Self 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 9370ad016ef..34c3961d5b4 100644 --- a/src/librustc_data_structures/lib.rs +++ b/src/librustc_data_structures/lib.rs @@ -50,6 +50,7 @@ pub mod fnv; pub mod tuple_slice; pub mod veccell; +pub mod control_flow_graph; // See comments in src/librustc/lib.rs #[doc(hidden)]