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.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>>();
|
||||
|
||||
Reference in New Issue
Block a user