diff --git a/lib/cretonne/src/cfg.rs b/lib/cretonne/src/cfg.rs index cfb29844d0..9b0f3f15e7 100644 --- a/lib/cretonne/src/cfg.rs +++ b/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::>(); 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); diff --git a/lib/cretonne/src/context.rs b/lib/cretonne/src/context.rs index 2360302ea2..8a94dd83fc 100644 --- a/lib/cretonne/src/context.rs +++ b/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(), + } } } diff --git a/lib/cretonne/src/dominator_tree.rs b/lib/cretonne/src/dominator_tree.rs index eaec78f367..02c9cecc84 100644 --- a/lib/cretonne/src/dominator_tree.rs +++ b/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); diff --git a/src/filetest/domtree.rs b/src/filetest/domtree.rs index 0a570e3253..72a4293df7 100644 --- a/src/filetest/domtree.rs +++ b/src/filetest/domtree.rs @@ -40,7 +40,7 @@ impl SubTest for TestDomtree { // Extract our own dominator tree from fn run(&self, func: Cow, 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. diff --git a/src/print_cfg.rs b/src/print_cfg.rs index 858ef4de23..ca6c9219f7 100644 --- a/src/print_cfg.rs +++ b/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), } } diff --git a/tests/cfg_traversal.rs b/tests/cfg_traversal.rs index 2bdeab2347..453e0f83b7 100644 --- a/tests/cfg_traversal.rs +++ b/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) { 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::>();