Browse Source
This test verifies the computed dominator tree against annotations. Move the existing testcases into filetests/ with the new syntax.pull/3/head
Jakob Stoklund Olesen
8 years ago
13 changed files with 232 additions and 186 deletions
@ -0,0 +1,13 @@ |
|||
test domtree |
|||
|
|||
function test(i32) { |
|||
ebb0(v0: i32): |
|||
jump ebb1 ; dominates: ebb1 |
|||
ebb1: |
|||
brz v0, ebb3 ; dominates: ebb3 |
|||
jump ebb2 ; dominates: ebb2 |
|||
ebb2: |
|||
jump ebb3 |
|||
ebb3: |
|||
return |
|||
} |
@ -1,7 +1,9 @@ |
|||
test domtree |
|||
|
|||
function test(i32) { |
|||
ebb0(v0: i32): ; dominates(0) |
|||
brz v0, ebb1 ; dominates(1,3,4,5) |
|||
jump ebb2 ; dominates(2) |
|||
ebb0(v0: i32): |
|||
brz v0, ebb1 ; dominates: ebb1 ebb3 ebb4 ebb5 |
|||
jump ebb2 ; dominates: ebb2 |
|||
ebb1: |
|||
jump ebb3 |
|||
ebb2: |
@ -1,13 +1,15 @@ |
|||
test domtree |
|||
|
|||
function test(i32) { |
|||
ebb0(v0: i32): ; dominates(0) |
|||
brz v0, ebb1 ; dominates(1,6) |
|||
brnz v0, ebb2 ; dominates(2,9) |
|||
jump ebb3 ; dominates(3) |
|||
ebb0(v0: i32): |
|||
brz v0, ebb1 ; dominates: ebb1 ebb6 |
|||
brnz v0, ebb2 ; dominates: ebb2 ebb9 |
|||
jump ebb3 ; dominates: ebb3 |
|||
ebb1: |
|||
jump ebb6 |
|||
ebb2: |
|||
brz v0, ebb4 ; dominates(4,7,8) |
|||
jump ebb5 ; dominates(5) |
|||
brz v0, ebb4 ; dominates: ebb4 ebb7 ebb8 |
|||
jump ebb5 ; dominates: ebb5 |
|||
ebb3: |
|||
jump ebb9 |
|||
ebb4: |
@ -0,0 +1,33 @@ |
|||
test domtree |
|||
|
|||
function test(i32) { |
|||
ebb0(v0: i32): |
|||
brz v0, ebb1 ; dominates: ebb1 |
|||
brnz v0, ebb2 ; dominates: ebb2 ebb5 |
|||
jump ebb3 ; dominates: ebb3 |
|||
ebb1: |
|||
jump ebb4 ; dominates: ebb4 |
|||
ebb2: |
|||
jump ebb5 |
|||
ebb3: |
|||
jump ebb5 |
|||
ebb4: |
|||
brz v0, ebb6 ; dominates: ebb6 ebb10 |
|||
jump ebb7 ; dominates: ebb7 |
|||
ebb5: |
|||
return |
|||
ebb6: |
|||
brz v0, ebb8 ; dominates: ebb11 ebb8 |
|||
brnz v0, ebb9 ; dominates: ebb9 |
|||
jump ebb10 |
|||
ebb7: |
|||
jump ebb10 |
|||
ebb8: |
|||
jump ebb11 |
|||
ebb9: |
|||
jump ebb11 |
|||
ebb10: |
|||
return |
|||
ebb11: |
|||
return |
|||
} |
@ -0,0 +1,41 @@ |
|||
test domtree |
|||
|
|||
function test(i32) { |
|||
ebb0(v0: i32): |
|||
brz v0, ebb13 ; dominates: ebb13 |
|||
jump ebb1 ; dominates: ebb1 |
|||
ebb1: |
|||
brz v0, ebb2 ; dominates: ebb2 ebb7 |
|||
brnz v0, ebb3 ; dominates: ebb3 |
|||
brz v0, ebb4 ; dominates: ebb4 |
|||
brnz v0, ebb5 ; dominates: ebb5 |
|||
jump ebb6 ; dominates: ebb6 |
|||
ebb2: |
|||
jump ebb7 |
|||
ebb3: |
|||
jump ebb7 |
|||
ebb4: |
|||
jump ebb7 |
|||
ebb5: |
|||
jump ebb7 |
|||
ebb6: |
|||
jump ebb7 |
|||
ebb7: |
|||
brnz v0, ebb8 ; dominates: ebb8 ebb12 |
|||
brz v0, ebb9 ; dominates: ebb9 |
|||
brnz v0, ebb10 ; dominates: ebb10 |
|||
jump ebb11 ; dominates: ebb11 |
|||
ebb8: |
|||
jump ebb12 |
|||
ebb9: |
|||
jump ebb12 |
|||
ebb10: |
|||
brz v0, ebb13 |
|||
jump ebb12 |
|||
ebb11: |
|||
jump ebb13 |
|||
ebb12: |
|||
return |
|||
ebb13: |
|||
return |
|||
} |
@ -0,0 +1,103 @@ |
|||
|
|||
//! Test command for verifying dominator trees.
|
|||
//!
|
|||
//! The `test domtree` test command looks for annotations on instructions like this:
|
|||
//!
|
|||
//! jump ebb3 ; dominates: ebb3
|
|||
//!
|
|||
//! This annotation means that the jump instruction is expected to be the immediate dominator of
|
|||
//! `ebb3`.
|
|||
//!
|
|||
//! We verify that the dominator tree annotations are complete and correct.
|
|||
//!
|
|||
|
|||
use std::collections::HashMap; |
|||
use std::borrow::{Borrow, Cow}; |
|||
use cretonne::ir::Function; |
|||
use cretonne::ir::entities::AnyEntity; |
|||
use cretonne::cfg::ControlFlowGraph; |
|||
use cretonne::dominator_tree::DominatorTree; |
|||
use cton_reader::TestCommand; |
|||
use filetest::subtest::{SubTest, Context, Result}; |
|||
use utils::match_directive; |
|||
|
|||
struct TestDomtree; |
|||
|
|||
pub fn subtest(parsed: &TestCommand) -> Result<Box<SubTest>> { |
|||
assert_eq!(parsed.command, "domtree"); |
|||
if !parsed.options.is_empty() { |
|||
Err(format!("No options allowed on {}", parsed)) |
|||
} else { |
|||
Ok(Box::new(TestDomtree)) |
|||
} |
|||
} |
|||
|
|||
impl SubTest for TestDomtree { |
|||
fn name(&self) -> Cow<str> { |
|||
Cow::from("domtree") |
|||
} |
|||
|
|||
// 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 domtree = DominatorTree::new(&cfg); |
|||
|
|||
// Build an expected domtree from the source annotations.
|
|||
let mut expected = HashMap::new(); |
|||
for comment in &context.details.comments { |
|||
if let Some(tail) = match_directive(comment.text, "dominates:") { |
|||
let inst = match comment.entity { |
|||
AnyEntity::Inst(inst) => inst, |
|||
_ => { |
|||
return Err(format!("annotation on non-inst {}: {}", |
|||
comment.entity, |
|||
comment.text)) |
|||
} |
|||
}; |
|||
for src_ebb in tail.split_whitespace() { |
|||
let ebb = match context.details.map.lookup_str(src_ebb) { |
|||
Some(AnyEntity::Ebb(ebb)) => ebb, |
|||
_ => return Err(format!("expected EBB: {}", src_ebb)), |
|||
}; |
|||
|
|||
// Annotations say that `inst` is the idom of `ebb`.
|
|||
if expected.insert(ebb, inst).is_some() { |
|||
return Err(format!("multiple dominators for {}", src_ebb)); |
|||
} |
|||
|
|||
// Compare to computed domtree.
|
|||
match domtree.idom(ebb) { |
|||
Some((_, got_inst)) if got_inst != inst => { |
|||
return Err(format!("mismatching idoms for {}:\n\ |
|||
want: {}, got: {}", |
|||
src_ebb, |
|||
inst, |
|||
got_inst)); |
|||
} |
|||
None => { |
|||
return Err(format!("mismatching idoms for {}:\n\ |
|||
want: {}, got: unreachable", |
|||
src_ebb, |
|||
inst)); |
|||
} |
|||
_ => {} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
// Now we know that everything in `expected` is consistent with `domtree`.
|
|||
// All other EBB's should be either unreachable or the entry block.
|
|||
for ebb in func.layout.ebbs().skip(1).filter(|ebb| !expected.contains_key(&ebb)) { |
|||
if let Some((_, got_inst)) = domtree.idom(ebb) { |
|||
return Err(format!("mismatching idoms for renumbered {}:\n\ |
|||
want: unrechable, got: {}", |
|||
ebb, |
|||
got_inst)); |
|||
} |
|||
} |
|||
|
|||
Ok(()) |
|||
} |
|||
} |
@ -1,96 +0,0 @@ |
|||
extern crate cretonne; |
|||
extern crate cton_reader; |
|||
extern crate glob; |
|||
extern crate regex; |
|||
|
|||
use std::env; |
|||
use glob::glob; |
|||
use regex::Regex; |
|||
use std::fs::File; |
|||
use std::io::Read; |
|||
use self::cretonne::ir::Ebb; |
|||
use self::cton_reader::parse_functions; |
|||
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::dominator_tree::DominatorTree; |
|||
|
|||
/// 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 = &parse_functions(function_source).unwrap()[0]; |
|||
let src_dtree = dominator_tree_from_source(&func, function_source); |
|||
|
|||
let cfg = ControlFlowGraph::new(&func); |
|||
let dtree = DominatorTree::new(&cfg); |
|||
|
|||
for ebb in func.layout.ebbs() { |
|||
assert_eq!(dtree.idom(ebb), src_dtree.idom(ebb)); |
|||
} |
|||
} |
|||
|
|||
#[test] |
|||
fn test_all() { |
|||
let testdir = format!("{}/tests/dominator_tree_testdata/*.cton", |
|||
env::current_dir().unwrap().display()); |
|||
|
|||
for entry in glob(&testdir).unwrap() { |
|||
let path = entry.unwrap(); |
|||
println!("Testing {:?}", path); |
|||
let mut file = File::open(&path).unwrap(); |
|||
let mut buffer = String::new(); |
|||
file.read_to_string(&mut buffer).unwrap(); |
|||
test_dominator_tree(&buffer); |
|||
} |
|||
} |
@ -1,11 +0,0 @@ |
|||
function test(i32) { |
|||
ebb0(v0: i32): ; dominates(0) |
|||
jump ebb1 ; dominates(1) |
|||
ebb1: |
|||
brz v0, ebb3 ; dominates(3) |
|||
jump ebb2 ; dominates(2) |
|||
ebb2: |
|||
jump ebb3 |
|||
ebb3: |
|||
return |
|||
} |
@ -1,31 +0,0 @@ |
|||
function test(i32) { |
|||
ebb0(v0: i32): ; dominates(0) |
|||
brz v0, ebb1 ; dominates(1) |
|||
brnz v0, ebb2 ; dominates(2,5) |
|||
jump ebb3 ; dominates(3) |
|||
ebb1: |
|||
jump ebb4 ; dominates(4) |
|||
ebb2: |
|||
jump ebb5 |
|||
ebb3: |
|||
jump ebb5 |
|||
ebb4: |
|||
brz v0, ebb6 ; dominates(6,10) |
|||
jump ebb7 ; dominates(7) |
|||
ebb5: |
|||
return |
|||
ebb6: |
|||
brz v0, ebb8 ; dominates(11,8) |
|||
brnz v0, ebb9 ; dominates(9) |
|||
jump ebb10 |
|||
ebb7: |
|||
jump ebb10 |
|||
ebb8: |
|||
jump ebb11 |
|||
ebb9: |
|||
jump ebb11 |
|||
ebb10: |
|||
return |
|||
ebb11: |
|||
return |
|||
} |
@ -1,39 +0,0 @@ |
|||
function test(i32) { |
|||
ebb0(v0: i32): ; dominates(0) |
|||
brz v0, ebb13 ; dominates(13) |
|||
jump ebb1 ; dominates(1) |
|||
ebb1: |
|||
brz v0, ebb2 ; dominates(2,7) |
|||
brnz v0, ebb3 ; dominates(3) |
|||
brz v0, ebb4 ; dominates(4) |
|||
brnz v0, ebb5 ; dominates(5) |
|||
jump ebb6 ; dominates(6) |
|||
ebb2: |
|||
jump ebb7 |
|||
ebb3: |
|||
jump ebb7 |
|||
ebb4: |
|||
jump ebb7 |
|||
ebb5: |
|||
jump ebb7 |
|||
ebb6: |
|||
jump ebb7 |
|||
ebb7: |
|||
brnz v0, ebb8 ; dominates(8,12) |
|||
brz v0, ebb9 ; dominates(9) |
|||
brnz v0, ebb10 ; dominates(10) |
|||
jump ebb11 ; dominates(11) |
|||
ebb8: |
|||
jump ebb12 |
|||
ebb9: |
|||
jump ebb12 |
|||
ebb10: |
|||
brz v0, ebb13 |
|||
jump ebb12 |
|||
ebb11: |
|||
jump ebb13 |
|||
ebb12: |
|||
return |
|||
ebb13: |
|||
return |
|||
} |
Loading…
Reference in new issue