Files
wasmtime/lib/cretonne/src/topo_order.rs
Dan Gohman 0c7316ae28 Lint fixes (#99)
* Replace a single-character string literal with a character literal.

* Use is_some() instead of comparing with Some(_).

* Add code-quotes around type names in comments.

* Use !...is_empty() instead of len() != 0.

* Tidy up redundant returns.

* Remove redundant .clone() calls.

* Remove unnecessary explicit lifetime parameters.

* Tidy up unnecessary '&'s.

* Add parens to make operator precedence explicit.

* Use debug_assert_eq instead of debug_assert with ==.

* Replace a &Vec argument with a &[...].

* Replace `a = a op b` with `a op= b`.

* Avoid unnecessary closures.

* Avoid .iter() and .iter_mut() for iterating over containers.

* Remove unneeded qualification.
2017-06-19 16:24:10 -07:00

126 lines
4.1 KiB
Rust

//! Topological order of EBBs, according to the dominator tree.
use dominator_tree::DominatorTree;
use ir::{Ebb, Layout};
use sparse_map::SparseSet;
/// Present EBBs in a topological order such that all dominating EBBs are guaranteed to be visited
/// before the current EBB.
///
/// There are many topological orders of the EBBs in a function, so it is possible to provide a
/// preferred order, and the `TopoOrder` will present EBBs in an order that is as close as possible
/// to the preferred order.
pub struct TopoOrder {
/// Preferred order of EBBs to visit.
preferred: Vec<Ebb>,
/// Next entry to get from `preferred`.
next: usize,
/// Set of visited EBBs.
visited: SparseSet<Ebb>,
/// Stack of EBBs to be visited next, already in `visited`.
stack: Vec<Ebb>,
}
impl TopoOrder {
/// Create a new empty topological order.
pub fn new() -> TopoOrder {
TopoOrder {
preferred: Vec::new(),
next: 0,
visited: SparseSet::new(),
stack: Vec::new(),
}
}
/// Reset and initialize with a preferred sequence of EBBs. The resulting topological order is
/// guaranteed to contain all of the EBBs in `preferred` as well as any dominators.
pub fn reset<Ebbs>(&mut self, preferred: Ebbs)
where Ebbs: IntoIterator<Item = Ebb>
{
self.preferred.clear();
self.preferred.extend(preferred);
self.next = 0;
self.visited.clear();
self.stack.clear();
}
/// Get the next EBB in the topological order.
///
/// Two things are guaranteed about the EBBs returned by this function:
///
/// - All EBBs in the `preferred` iterator given to `reset` will be returned.
/// - All dominators are visited before the EBB returned.
pub fn next(&mut self, layout: &Layout, domtree: &DominatorTree) -> Option<Ebb> {
// Any entries in `stack` should be returned immediately. They have already been added to
// `visited`.
while self.stack.is_empty() {
match self.preferred.get(self.next).cloned() {
None => return None,
Some(mut ebb) => {
// We have the next EBB in the preferred order.
self.next += 1;
// Push it along with any non-visited dominators.
while self.visited.insert(ebb).is_none() {
self.stack.push(ebb);
match domtree.idom(ebb) {
Some(idom) => ebb = layout.inst_ebb(idom).expect("idom not in layout"),
None => break,
}
}
}
}
}
self.stack.pop()
}
}
#[cfg(test)]
mod test {
use flowgraph::ControlFlowGraph;
use dominator_tree::DominatorTree;
use ir::{Function, InstBuilder, Cursor};
use std::iter;
use super::*;
#[test]
fn empty() {
let func = Function::new();
let cfg = ControlFlowGraph::with_function(&func);
let domtree = DominatorTree::with_function(&func, &cfg);
let mut topo = TopoOrder::new();
assert_eq!(topo.next(&func.layout, &domtree), None);
topo.reset(func.layout.ebbs());
assert_eq!(topo.next(&func.layout, &domtree), None);
}
#[test]
fn simple() {
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
let ebb1 = func.dfg.make_ebb();
{
let dfg = &mut func.dfg;
let cur = &mut Cursor::new(&mut func.layout);
cur.insert_ebb(ebb0);
dfg.ins(cur).jump(ebb1, &[]);
cur.insert_ebb(ebb1);
dfg.ins(cur).jump(ebb1, &[]);
}
let cfg = ControlFlowGraph::with_function(&func);
let domtree = DominatorTree::with_function(&func, &cfg);
let mut topo = TopoOrder::new();
topo.reset(iter::once(ebb1));
assert_eq!(topo.next(&func.layout, &domtree), Some(ebb0));
assert_eq!(topo.next(&func.layout, &domtree), Some(ebb1));
assert_eq!(topo.next(&func.layout, &domtree), None);
}
}