Add basic block information to the dominator tree.
To be complete the dominator tree must represent idoms as Ebb, Inst pairs, i.e. bais blocks.
This commit is contained in:
@@ -2,10 +2,11 @@
|
||||
|
||||
use cfg::*;
|
||||
use ir::Ebb;
|
||||
use ir::entities::NO_INST;
|
||||
use entity_map::{EntityMap, Keys};
|
||||
|
||||
pub struct DominatorTree {
|
||||
data: EntityMap<Ebb, Option<Ebb>>,
|
||||
data: EntityMap<Ebb, Option<BasicBlock>>,
|
||||
}
|
||||
|
||||
impl DominatorTree {
|
||||
@@ -28,7 +29,7 @@ impl DominatorTree {
|
||||
let mut changed = false;
|
||||
|
||||
if len > 0 {
|
||||
data[ebbs[0]] = Some(ebbs[0]);
|
||||
data[ebbs[0]] = Some((ebbs[0], NO_INST));
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -39,20 +40,21 @@ impl DominatorTree {
|
||||
let preds = cfg.get_predecessors(ebb);
|
||||
let mut new_idom = None;
|
||||
|
||||
for &(p, _) in preds {
|
||||
for &(p_ebb, _) in preds {
|
||||
if new_idom == None {
|
||||
new_idom = Some(p);
|
||||
new_idom = Some((p_ebb, NO_INST));
|
||||
continue;
|
||||
}
|
||||
// If this predecessor `p` has an idom available find its common
|
||||
// If this predecessor has an idom available find its common
|
||||
// ancestor with the current value of new_idom.
|
||||
if let Some(_) = data[p] {
|
||||
if let Some(_) = data[p_ebb] {
|
||||
new_idom = match new_idom {
|
||||
Some(cur_idom) => {
|
||||
Some(DominatorTree::intersect(&mut data,
|
||||
&postorder_map,
|
||||
p,
|
||||
cur_idom))
|
||||
Some((DominatorTree::intersect(&mut data,
|
||||
&postorder_map,
|
||||
p_ebb,
|
||||
cur_idom.0),
|
||||
NO_INST))
|
||||
}
|
||||
None => panic!("A 'current idom' should have been set!"),
|
||||
}
|
||||
@@ -73,11 +75,36 @@ impl DominatorTree {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// At this point the basic blocks in the tree are incomplete
|
||||
// since they have all been set with NO_INST. Here we add instructions
|
||||
// by iterating through each Ebb -> BasicBlock mapping in the dominator
|
||||
// tree and replacing the basic block with a corresponding predecessor
|
||||
// from the Ebb (on the left hand side).
|
||||
//
|
||||
// The predecessor chosen should have the lowest instruction number and
|
||||
// an Ebb which matches the Ebb from the dummy basic block. Because
|
||||
// extended basic blocks have a single entry point this will always
|
||||
// result in the correct basic block being chosen.
|
||||
for lhs_ebb in ebbs {
|
||||
let rhs_bb = data[lhs_ebb].unwrap();
|
||||
for pred_bb in cfg.get_predecessors(lhs_ebb) {
|
||||
if rhs_bb.0 == pred_bb.0 {
|
||||
// Predecessors are added in order while iterating through
|
||||
// instructions from lowest to highest. Because of this,
|
||||
// the first match we encounter will have the lowest instruction
|
||||
// number.
|
||||
data[lhs_ebb] = Some(pred_bb.clone());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DominatorTree { data: data }
|
||||
}
|
||||
|
||||
/// Find the common dominator of two ebbs.
|
||||
fn intersect(data: &EntityMap<Ebb, Option<Ebb>>,
|
||||
fn intersect(data: &EntityMap<Ebb, Option<BasicBlock>>,
|
||||
ordering: &EntityMap<Ebb, usize>,
|
||||
first: Ebb,
|
||||
second: Ebb)
|
||||
@@ -91,10 +118,10 @@ impl DominatorTree {
|
||||
// self.data[b] to contain non-None entries.
|
||||
while a != b {
|
||||
while ordering[a] < ordering[b] {
|
||||
a = data[a].unwrap();
|
||||
a = data[a].unwrap().0;
|
||||
}
|
||||
while ordering[b] < ordering[a] {
|
||||
b = data[b].unwrap();
|
||||
b = data[b].unwrap().0;
|
||||
}
|
||||
}
|
||||
a
|
||||
@@ -102,7 +129,7 @@ impl DominatorTree {
|
||||
|
||||
/// Returns the immediate dominator of some ebb or None if the
|
||||
/// node is unreachable.
|
||||
pub fn idom(&self, ebb: Ebb) -> Option<Ebb> {
|
||||
pub fn idom(&self, ebb: Ebb) -> Option<BasicBlock> {
|
||||
self.data[ebb].clone()
|
||||
}
|
||||
|
||||
@@ -116,6 +143,7 @@ impl DominatorTree {
|
||||
mod test {
|
||||
use super::*;
|
||||
use ir::Function;
|
||||
use ir::entities::NO_INST;
|
||||
use cfg::ControlFlowGraph;
|
||||
use test_utils::make_inst;
|
||||
|
||||
@@ -153,9 +181,9 @@ mod test {
|
||||
let dt = DominatorTree::new(&cfg);
|
||||
|
||||
assert_eq!(func.layout.entry_block().unwrap(), ebb3);
|
||||
assert_eq!(dt.idom(ebb3).unwrap(), ebb3);
|
||||
assert_eq!(dt.idom(ebb1).unwrap(), ebb3);
|
||||
assert_eq!(dt.idom(ebb2).unwrap(), ebb1);
|
||||
assert_eq!(dt.idom(ebb0).unwrap(), ebb1);
|
||||
assert_eq!(dt.idom(ebb3).unwrap(), (ebb3, NO_INST));
|
||||
assert_eq!(dt.idom(ebb1).unwrap(), (ebb3, jmp_ebb3_ebb1));
|
||||
assert_eq!(dt.idom(ebb2).unwrap(), (ebb1, jmp_ebb1_ebb2));
|
||||
assert_eq!(dt.idom(ebb0).unwrap(), (ebb1, br_ebb1_ebb0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
extern crate cretonne;
|
||||
extern crate cton_reader;
|
||||
|
||||
use self::cton_reader::parser::Parser;
|
||||
use self::cretonne::ir::Ebb;
|
||||
use self::cton_reader::parser::Parser;
|
||||
use self::cretonne::ir::entities::NO_INST;
|
||||
use self::cretonne::cfg::ControlFlowGraph;
|
||||
use self::cretonne::ir::instructions::BranchInfo;
|
||||
use self::cretonne::dominator_tree::DominatorTree;
|
||||
|
||||
fn test_dominator_tree(function_source: &str, idoms: Vec<u32>) {
|
||||
@@ -12,9 +14,36 @@ fn test_dominator_tree(function_source: &str, idoms: Vec<u32>) {
|
||||
let dtree = DominatorTree::new(&cfg);
|
||||
assert_eq!(dtree.ebbs().collect::<Vec<_>>().len(), idoms.len());
|
||||
for (i, j) in idoms.iter().enumerate() {
|
||||
let ebb = Ebb::with_number(i.clone() as u32);
|
||||
let idom = Ebb::with_number(*j);
|
||||
assert_eq!(dtree.idom(ebb.unwrap()), idom);
|
||||
let ebb = Ebb::with_number(i.clone() as u32).unwrap();
|
||||
let idom_ebb = Ebb::with_number(*j).unwrap();
|
||||
let mut idom_inst = NO_INST;
|
||||
|
||||
// Find the first branch/jump instruction which points to the idom_ebb
|
||||
// and use it to denote our idom basic block.
|
||||
for inst in func.layout.ebb_insts(idom_ebb) {
|
||||
match func.dfg[inst].analyze_branch() {
|
||||
BranchInfo::SingleDest(dest, _) => {
|
||||
if dest == ebb {
|
||||
idom_inst = inst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BranchInfo::Table(jt) => {
|
||||
for (_, dest) in func.jump_tables[jt].entries() {
|
||||
if dest == ebb {
|
||||
idom_inst = inst;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// We already found our inst!
|
||||
if idom_inst != NO_INST {
|
||||
break;
|
||||
}
|
||||
}
|
||||
BranchInfo::NotABranch => {}
|
||||
}
|
||||
}
|
||||
assert_eq!(dtree.idom(ebb).unwrap(), (idom_ebb, idom_inst));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user