Modify the dominator tree's intersect method to interact with Basic Blocks
Corresponding changes to test cases are also included.
This commit is contained in:
@@ -14,3 +14,4 @@ cretonne = { path = "../libcretonne" }
|
||||
cretonne-reader = { path = "../libreader" }
|
||||
docopt = "0.6.80"
|
||||
rustc-serialize = "0.3.19"
|
||||
regex = "0.1.73"
|
||||
|
||||
@@ -1,49 +1,77 @@
|
||||
extern crate cretonne;
|
||||
extern crate cton_reader;
|
||||
extern crate regex;
|
||||
|
||||
use regex::Regex;
|
||||
use self::cretonne::ir::Ebb;
|
||||
use self::cton_reader::parser::Parser;
|
||||
use self::cretonne::ir::function::Function;
|
||||
use self::cretonne::entity_map::EntityMap;
|
||||
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>) {
|
||||
/// Construct a dominator tree from specially formatted comments in
|
||||
/// cton source. Each line with a jump/branch instruction should
|
||||
/// have a comment of the format: `dominates(n, ..., N)`, where each `n`
|
||||
/// is the Ebb number for which this instruction is the immediate dominator.
|
||||
fn dominator_tree_from_source(func: &Function, function_source: &str) -> DominatorTree {
|
||||
let ebb_re = Regex::new("^[ \t]*ebb[0-9]+.*:").unwrap();
|
||||
let dom_re = Regex::new("dominates\\(([0-9,]+)\\)").unwrap();
|
||||
let inst_re = Regex::new("^[ \t]*[a-zA-Z0-9]+[^{}]*").unwrap();
|
||||
let func_re = Regex::new("^[ \t]*function.*").unwrap();
|
||||
|
||||
let ebbs = func.layout.ebbs().collect::<Vec<_>>();
|
||||
let mut data = EntityMap::with_capacity(ebbs.len());
|
||||
|
||||
if ebbs.len() < 1 {
|
||||
return DominatorTree::from_data(data);
|
||||
}
|
||||
|
||||
let mut ebb_offset = 0;
|
||||
let mut inst_offset = 0;
|
||||
|
||||
let mut cur_ebb = ebbs[0];
|
||||
let mut insts = func.layout.ebb_insts(ebbs[ebb_offset]).collect::<Vec<_>>();
|
||||
|
||||
for line in function_source.lines() {
|
||||
if ebb_re.is_match(line) {
|
||||
cur_ebb = ebbs[ebb_offset];
|
||||
insts = func.layout.ebb_insts(cur_ebb).collect::<Vec<_>>();
|
||||
ebb_offset += 1;
|
||||
inst_offset = 0;
|
||||
} else if inst_re.is_match(line) && !func_re.is_match(line) {
|
||||
inst_offset += 1;
|
||||
}
|
||||
match dom_re.captures(line) {
|
||||
Some(caps) => {
|
||||
for s in caps.at(1).unwrap().split(",") {
|
||||
let this_ebb = Ebb::with_number(s.parse::<u32>().unwrap()).unwrap();
|
||||
let inst = if inst_offset == 0 {
|
||||
NO_INST
|
||||
} else {
|
||||
insts[inst_offset - 1].clone()
|
||||
};
|
||||
data[this_ebb] = Some((cur_ebb.clone(), inst));
|
||||
}
|
||||
},
|
||||
None => continue,
|
||||
};
|
||||
|
||||
}
|
||||
DominatorTree::from_data(data)
|
||||
}
|
||||
|
||||
fn test_dominator_tree(function_source: &str) {
|
||||
|
||||
let func = &Parser::parse(function_source).unwrap()[0];
|
||||
let src_dtree = dominator_tree_from_source(&func, function_source);
|
||||
|
||||
let cfg = ControlFlowGraph::new(&func);
|
||||
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).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));
|
||||
for ebb in func.layout.ebbs() {
|
||||
assert_eq!(dtree.idom(ebb), src_dtree.idom(ebb));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,26 +79,26 @@ fn test_dominator_tree(function_source: &str, idoms: Vec<u32>) {
|
||||
fn basic() {
|
||||
test_dominator_tree("
|
||||
function test(i32) {
|
||||
ebb0(v0: i32):
|
||||
jump ebb1
|
||||
ebb0(v0: i32): ; dominates(0)
|
||||
jump ebb1 ; dominates(1)
|
||||
ebb1:
|
||||
brz v0, ebb3
|
||||
jump ebb2
|
||||
brz v0, ebb3 ; dominates(3)
|
||||
jump ebb2 ; dominates(2)
|
||||
ebb2:
|
||||
jump ebb3
|
||||
ebb3:
|
||||
return
|
||||
}
|
||||
", vec![0, 0, 1, 1]);
|
||||
");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn loops() {
|
||||
test_dominator_tree("
|
||||
function test(i32) {
|
||||
ebb0(v0: i32):
|
||||
brz v0, ebb1
|
||||
jump ebb2
|
||||
ebb0(v0: i32): ; dominates(0)
|
||||
brz v0, ebb1 ; dominates(1,3,4,5)
|
||||
jump ebb2 ; dominates(2)
|
||||
ebb1:
|
||||
jump ebb3
|
||||
ebb2:
|
||||
@@ -85,5 +113,5 @@ fn loops() {
|
||||
brz v0, ebb4
|
||||
return
|
||||
}
|
||||
", vec![0, 0, 0, 0, 0, 0]);
|
||||
");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user