Browse Source

Make the ControlFlowGraph reusable.

Move the flow graph computation into a compute method which can be
called with multiple functions.

This allows us to reuse the ControlFlowGraph memory and keep an instance
in the Context.
pull/3/head
Jakob Stoklund Olesen 8 years ago
parent
commit
0f29fc7a52
  1. 39
      lib/cretonne/src/cfg.rs
  2. 9
      lib/cretonne/src/context.rs
  3. 4
      lib/cretonne/src/dominator_tree.rs
  4. 2
      src/filetest/domtree.rs
  5. 2
      src/print_cfg.rs
  6. 2
      tests/cfg_traversal.rs

39
lib/cretonne/src/cfg.rs

@ -50,31 +50,44 @@ pub struct ControlFlowGraph {
}
impl ControlFlowGraph {
/// During initialization mappings will be generated for any existing
/// blocks within the CFG's associated function.
pub fn new(func: &Function) -> ControlFlowGraph {
/// Allocate a new blank control flow graph.
pub fn new() -> ControlFlowGraph {
ControlFlowGraph {
entry_block: None,
data: EntityMap::new(),
}
}
let mut cfg = ControlFlowGraph {
data: EntityMap::with_capacity(func.dfg.num_ebbs()),
entry_block: func.layout.entry_block(),
};
/// Allocate and compute the control flow graph for `func`.
pub fn with_function(func: &Function) -> ControlFlowGraph {
let mut cfg = ControlFlowGraph::new();
cfg.compute(func);
cfg
}
/// Compute the control flow graph of `func`.
///
/// This will clear and overwrite any information already stored in this data structure.
pub fn compute(&mut self, func: &Function) {
self.entry_block = func.layout.entry_block();
self.data.clear();
self.data.resize(func.dfg.num_ebbs());
for ebb in &func.layout {
for inst in func.layout.ebb_insts(ebb) {
match func.dfg[inst].analyze_branch() {
BranchInfo::SingleDest(dest, _) => {
cfg.add_edge((ebb, inst), dest);
self.add_edge((ebb, inst), dest);
}
BranchInfo::Table(jt) => {
for (_, dest) in func.jump_tables[jt].entries() {
cfg.add_edge((ebb, inst), dest);
self.add_edge((ebb, inst), dest);
}
}
BranchInfo::NotABranch => {}
}
}
}
cfg
}
fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
@ -140,7 +153,7 @@ mod tests {
#[test]
fn empty() {
let func = Function::new();
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
assert_eq!(None, cfg.ebbs().next());
}
@ -154,7 +167,7 @@ mod tests {
func.layout.append_ebb(ebb1);
func.layout.append_ebb(ebb2);
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
let nodes = cfg.ebbs().collect::<Vec<_>>();
assert_eq!(nodes.len(), 3);
@ -194,7 +207,7 @@ mod tests {
cur.insert_ebb(ebb2);
}
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
let ebb0_predecessors = cfg.get_predecessors(ebb0);
let ebb1_predecessors = cfg.get_predecessors(ebb1);

9
lib/cretonne/src/context.rs

@ -4,12 +4,16 @@
//! deallocating the data structures needed for compilation. The `Context` struct is used to hold
//! on to memory allocations between function compilations.
use cfg::ControlFlowGraph;
use ir::Function;
/// Persistent data structures and compilation pipeline.
pub struct Context {
/// The function we're compiling.
pub func: Function,
/// The control flow graph of `func`.
pub cfg: ControlFlowGraph,
}
impl Context {
@ -18,6 +22,9 @@ impl Context {
/// The returned instance should be reused for compiling multiple functions in order to avoid
/// needless allocator thrashing.
pub fn new() -> Context {
Context { func: Function::new() }
Context {
func: Function::new(),
cfg: ControlFlowGraph::new(),
}
}
}

4
lib/cretonne/src/dominator_tree.rs

@ -203,7 +203,7 @@ mod test {
#[test]
fn empty() {
let func = Function::new();
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
let dtree = DominatorTree::new(&func, &cfg);
assert_eq!(0, dtree.nodes.keys().count());
}
@ -238,7 +238,7 @@ mod test {
cur.insert_ebb(ebb0);
}
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
let dt = DominatorTree::new(&func, &cfg);
assert_eq!(func.layout.entry_block().unwrap(), ebb3);

2
src/filetest/domtree.rs

@ -40,7 +40,7 @@ impl SubTest for TestDomtree {
// Extract our own dominator tree from
fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> {
let func = func.borrow();
let cfg = ControlFlowGraph::new(func);
let cfg = ControlFlowGraph::with_function(func);
let domtree = DominatorTree::new(func, &cfg);
// Build an expected domtree from the source annotations.

2
src/print_cfg.rs

@ -33,7 +33,7 @@ impl<'a> CFGPrinter<'a> {
pub fn new(func: &'a Function) -> CFGPrinter<'a> {
CFGPrinter {
func: func,
cfg: ControlFlowGraph::new(func),
cfg: ControlFlowGraph::with_function(func),
}
}

2
tests/cfg_traversal.rs

@ -8,7 +8,7 @@ use self::cretonne::entity_map::EntityMap;
fn test_reverse_postorder_traversal(function_source: &str, ebb_order: Vec<u32>) {
let func = &parse_functions(function_source).unwrap()[0];
let cfg = ControlFlowGraph::new(&func);
let cfg = ControlFlowGraph::with_function(&func);
let ebbs = ebb_order.iter()
.map(|n| Ebb::with_number(*n).unwrap())
.collect::<Vec<Ebb>>();

Loading…
Cancel
Save