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 {
|
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);
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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>>();
|
||||||
|
|||||||
Reference in New Issue
Block a user