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 { impl ControlFlowGraph {
/// During initialization mappings will be generated for any existing /// Allocate a new blank control flow graph.
/// blocks within the CFG's associated function. pub fn new() -> ControlFlowGraph {
pub fn new(func: &Function) -> ControlFlowGraph { ControlFlowGraph {
entry_block: None,
data: EntityMap::new(),
}
}
let mut cfg = ControlFlowGraph { /// Allocate and compute the control flow graph for `func`.
data: EntityMap::with_capacity(func.dfg.num_ebbs()), pub fn with_function(func: &Function) -> ControlFlowGraph {
entry_block: func.layout.entry_block(), 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 ebb in &func.layout {
for inst in func.layout.ebb_insts(ebb) { for inst in func.layout.ebb_insts(ebb) {
match func.dfg[inst].analyze_branch() { match func.dfg[inst].analyze_branch() {
BranchInfo::SingleDest(dest, _) => { BranchInfo::SingleDest(dest, _) => {
cfg.add_edge((ebb, inst), dest); self.add_edge((ebb, inst), dest);
} }
BranchInfo::Table(jt) => { BranchInfo::Table(jt) => {
for (_, dest) in func.jump_tables[jt].entries() { for (_, dest) in func.jump_tables[jt].entries() {
cfg.add_edge((ebb, inst), dest); self.add_edge((ebb, inst), dest);
} }
} }
BranchInfo::NotABranch => {} BranchInfo::NotABranch => {}
} }
} }
} }
cfg
} }
fn add_edge(&mut self, from: BasicBlock, to: Ebb) { fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
@ -140,7 +153,7 @@ mod tests {
#[test] #[test]
fn empty() { fn empty() {
let func = Function::new(); let func = Function::new();
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
assert_eq!(None, cfg.ebbs().next()); assert_eq!(None, cfg.ebbs().next());
} }
@ -154,7 +167,7 @@ mod tests {
func.layout.append_ebb(ebb1); func.layout.append_ebb(ebb1);
func.layout.append_ebb(ebb2); func.layout.append_ebb(ebb2);
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
let nodes = cfg.ebbs().collect::<Vec<_>>(); let nodes = cfg.ebbs().collect::<Vec<_>>();
assert_eq!(nodes.len(), 3); assert_eq!(nodes.len(), 3);
@ -194,7 +207,7 @@ mod tests {
cur.insert_ebb(ebb2); cur.insert_ebb(ebb2);
} }
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
let ebb0_predecessors = cfg.get_predecessors(ebb0); let ebb0_predecessors = cfg.get_predecessors(ebb0);
let ebb1_predecessors = cfg.get_predecessors(ebb1); 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 //! deallocating the data structures needed for compilation. The `Context` struct is used to hold
//! on to memory allocations between function compilations. //! on to memory allocations between function compilations.
use cfg::ControlFlowGraph;
use ir::Function; use ir::Function;
/// Persistent data structures and compilation pipeline. /// Persistent data structures and compilation pipeline.
pub struct Context { pub struct Context {
/// The function we're compiling. /// The function we're compiling.
pub func: Function, pub func: Function,
/// The control flow graph of `func`.
pub cfg: ControlFlowGraph,
} }
impl Context { impl Context {
@ -18,6 +22,9 @@ impl Context {
/// The returned instance should be reused for compiling multiple functions in order to avoid /// The returned instance should be reused for compiling multiple functions in order to avoid
/// needless allocator thrashing. /// needless allocator thrashing.
pub fn new() -> Context { 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] #[test]
fn empty() { fn empty() {
let func = Function::new(); let func = Function::new();
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
let dtree = DominatorTree::new(&func, &cfg); let dtree = DominatorTree::new(&func, &cfg);
assert_eq!(0, dtree.nodes.keys().count()); assert_eq!(0, dtree.nodes.keys().count());
} }
@ -238,7 +238,7 @@ mod test {
cur.insert_ebb(ebb0); cur.insert_ebb(ebb0);
} }
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
let dt = DominatorTree::new(&func, &cfg); let dt = DominatorTree::new(&func, &cfg);
assert_eq!(func.layout.entry_block().unwrap(), ebb3); 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 // Extract our own dominator tree from
fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> { fn run(&self, func: Cow<Function>, context: &Context) -> Result<()> {
let func = func.borrow(); let func = func.borrow();
let cfg = ControlFlowGraph::new(func); let cfg = ControlFlowGraph::with_function(func);
let domtree = DominatorTree::new(func, &cfg); let domtree = DominatorTree::new(func, &cfg);
// Build an expected domtree from the source annotations. // 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> { pub fn new(func: &'a Function) -> CFGPrinter<'a> {
CFGPrinter { CFGPrinter {
func: func, 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>) { fn test_reverse_postorder_traversal(function_source: &str, ebb_order: Vec<u32>) {
let func = &parse_functions(function_source).unwrap()[0]; let func = &parse_functions(function_source).unwrap()[0];
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::with_function(&func);
let ebbs = ebb_order.iter() let ebbs = ebb_order.iter()
.map(|n| Ebb::with_number(*n).unwrap()) .map(|n| Ebb::with_number(*n).unwrap())
.collect::<Vec<Ebb>>(); .collect::<Vec<Ebb>>();

Loading…
Cancel
Save