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`.
This commit is contained in:
commit
a0f572e98b
14 changed files with 871 additions and 3 deletions
|
@ -15,7 +15,7 @@ use mir::repr::{Mir, BasicBlock};
|
||||||
|
|
||||||
use rustc_serialize as serialize;
|
use rustc_serialize as serialize;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Cache {
|
pub struct Cache {
|
||||||
predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
|
predecessors: RefCell<Option<IndexVec<BasicBlock, Vec<BasicBlock>>>>
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,9 @@ use graphviz::IntoCow;
|
||||||
use middle::const_val::ConstVal;
|
use middle::const_val::ConstVal;
|
||||||
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
|
use rustc_const_math::{ConstUsize, ConstInt, ConstMathErr};
|
||||||
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
|
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 hir::def_id::DefId;
|
||||||
use ty::subst::Substs;
|
use ty::subst::Substs;
|
||||||
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
use ty::{self, AdtDef, ClosureSubsts, FnOutput, Region, Ty};
|
||||||
|
@ -24,6 +27,7 @@ use std::cell::Ref;
|
||||||
use std::fmt::{self, Debug, Formatter, Write};
|
use std::fmt::{self, Debug, Formatter, Write};
|
||||||
use std::{iter, u32};
|
use std::{iter, u32};
|
||||||
use std::ops::{Index, IndexMut};
|
use std::ops::{Index, IndexMut};
|
||||||
|
use std::vec::IntoIter;
|
||||||
use syntax::ast::{self, Name};
|
use syntax::ast::{self, Name};
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
|
|
||||||
|
@ -54,7 +58,7 @@ macro_rules! newtype_index {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lowered representation of a single function.
|
/// Lowered representation of a single function.
|
||||||
#[derive(Clone, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
|
||||||
pub struct Mir<'tcx> {
|
pub struct Mir<'tcx> {
|
||||||
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
|
/// List of basic blocks. References to basic block use a newtyped index type `BasicBlock`
|
||||||
/// that indexes into this vector.
|
/// that indexes into this vector.
|
||||||
|
@ -145,6 +149,11 @@ impl<'tcx> Mir<'tcx> {
|
||||||
Ref::map(self.predecessors(), |p| &p[bb])
|
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)
|
/// 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
|
/// 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.
|
/// 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 {
|
fn item_path_str(def_id: DefId) -> String {
|
||||||
ty::tls::with(|tcx| tcx.item_path_str(def_id))
|
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>;
|
||||||
|
}
|
||||||
|
|
|
@ -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 <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()
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <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));
|
||||||
|
}
|
||||||
|
|
|
@ -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 <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
|
||||||
|
}
|
|
@ -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 <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]);
|
||||||
|
}
|
||||||
|
|
45
src/librustc_data_structures/control_flow_graph/mod.rs
Normal file
45
src/librustc_data_structures/control_flow_graph/mod.rs
Normal file
|
@ -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 <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>;
|
||||||
|
}
|
|
@ -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 <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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <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));
|
||||||
|
}
|
43
src/librustc_data_structures/control_flow_graph/reference.rs
Normal file
43
src/librustc_data_structures/control_flow_graph/reference.rs
Normal file
|
@ -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 <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;
|
||||||
|
}
|
78
src/librustc_data_structures/control_flow_graph/test.rs
Normal file
78
src/librustc_data_structures/control_flow_graph/test.rs
Normal file
|
@ -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 <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>>;
|
||||||
|
}
|
||||||
|
|
59
src/librustc_data_structures/control_flow_graph/transpose.rs
Normal file
59
src/librustc_data_structures/control_flow_graph/transpose.rs
Normal file
|
@ -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 <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;
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
use std::iter::{self, FromIterator};
|
use std::iter::{self, FromIterator};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
@ -20,7 +21,7 @@ use rustc_serialize as serialize;
|
||||||
/// Represents some newtyped `usize` wrapper.
|
/// Represents some newtyped `usize` wrapper.
|
||||||
///
|
///
|
||||||
/// (purpose: avoid mixing indexes for different bitvector domains.)
|
/// (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 new(usize) -> Self;
|
||||||
fn index(self) -> usize;
|
fn index(self) -> usize;
|
||||||
}
|
}
|
||||||
|
@ -76,6 +77,13 @@ impl<I: Idx, T> IndexVec<I, T> {
|
||||||
IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
|
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]
|
#[inline]
|
||||||
pub fn push(&mut self, d: T) -> I {
|
pub fn push(&mut self, d: T) -> I {
|
||||||
let idx = I::new(self.len());
|
let idx = I::new(self.len());
|
||||||
|
|
|
@ -50,6 +50,7 @@ pub mod unify;
|
||||||
pub mod fnv;
|
pub mod fnv;
|
||||||
pub mod tuple_slice;
|
pub mod tuple_slice;
|
||||||
pub mod veccell;
|
pub mod veccell;
|
||||||
|
pub mod control_flow_graph;
|
||||||
|
|
||||||
// See comments in src/librustc/lib.rs
|
// See comments in src/librustc/lib.rs
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue