From 967a7c64d4468273f36a3130dbf5e34481e65db9 Mon Sep 17 00:00:00 2001 From: Morgan Phillips Date: Sun, 31 Jul 2016 21:40:11 -0700 Subject: [PATCH] Add a dominator tree implementation. --- cranelift/src/libcretonne/cfg.rs | 2 +- cranelift/src/libcretonne/dominator_tree.rs | 138 ++++++++++++++++++ cranelift/src/libcretonne/lib.rs | 2 +- .../src/libcretonne/tests/dominator_tree.rs | 60 ++++++++ cranelift/src/libcretonne/tests/lib.rs | 1 + 5 files changed, 201 insertions(+), 2 deletions(-) create mode 100644 cranelift/src/libcretonne/dominator_tree.rs create mode 100644 cranelift/src/libcretonne/tests/dominator_tree.rs diff --git a/cranelift/src/libcretonne/cfg.rs b/cranelift/src/libcretonne/cfg.rs index 25b5f2409a..28a39861e2 100644 --- a/cranelift/src/libcretonne/cfg.rs +++ b/cranelift/src/libcretonne/cfg.rs @@ -89,7 +89,7 @@ impl ControlFlowGraph { self.data[to].predecessors.push(from); } - fn get_predecessors(&self, ebb: Ebb) -> &Vec { + pub fn get_predecessors(&self, ebb: Ebb) -> &Vec { &self.data[ebb].predecessors } diff --git a/cranelift/src/libcretonne/dominator_tree.rs b/cranelift/src/libcretonne/dominator_tree.rs new file mode 100644 index 0000000000..e4569ea112 --- /dev/null +++ b/cranelift/src/libcretonne/dominator_tree.rs @@ -0,0 +1,138 @@ +/// ! A Dominator Tree represented as mappings of Ebbs to their immediate dominator. + +use cfg::*; +use ir::entities::Ebb; +use entity_map::EntityMap; + +pub struct DominatorTree { + data: EntityMap>, +} + +impl DominatorTree { + pub fn new(cfg: &ControlFlowGraph) -> DominatorTree { + let mut dt = DominatorTree { data: EntityMap::new() }; + dt.build(cfg); + dt + } + + pub fn build(&mut self, cfg: &ControlFlowGraph) { + let reverse_postorder_map = cfg.reverse_postorder_ebbs(); + let ebbs = reverse_postorder_map.keys().collect::>(); + let len = reverse_postorder_map.len(); + + for (i, ebb) in ebbs.iter().enumerate() { + if i > 0 { + self.data.push(None); + } else { + self.data.push(Some(ebb.clone())); + } + } + + let mut changed = len > 0; + + while changed { + changed = false; + for i in 1..len { + let ebb = ebbs[i]; + let preds = cfg.get_predecessors(ebb); + let mut new_idom = None; + + for &(p, _) in preds { + if new_idom == None { + new_idom = Some(p); + continue; + } + if let Some(_) = self.data[p] { + new_idom = + Some(self.intersect(&reverse_postorder_map, p, new_idom.unwrap())); + } + } + match self.data[ebb] { + None => { + self.data[ebb] = new_idom; + changed = true; + } + Some(idom) => { + // Old idom != New idom + if idom != new_idom.unwrap() { + self.data[ebb] = new_idom; + changed = true; + } + } + } + } + } + } + + fn intersect(&self, ordering: &EntityMap, first: Ebb, second: Ebb) -> Ebb { + println!("A {} B {}", first, second); + let mut a = first; + let mut b = second; + while a != b { + while ordering[a] < ordering[b] { + a = self.data[a].unwrap(); + } + while ordering[b] < ordering[a] { + b = self.data[b].unwrap(); + } + } + a + } + + pub fn idom(&self, ebb: Ebb) -> Option { + self.data[ebb].clone() + } + + pub fn len(&self) -> usize { + self.data.len() + } +} + +#[cfg(test)] +mod test { + use super::*; + use ir::Function; + use cfg::ControlFlowGraph; + use test_utils::make_inst; + + #[test] + fn empty() { + let func = Function::new(); + let cfg = ControlFlowGraph::new(&func); + let dtree = DominatorTree::new(&cfg); + assert_eq!(dtree.len(), 0); + } + + #[test] + fn non_zero_entry_block() { + let mut func = Function::new(); + let ebb3 = func.dfg.make_ebb(); + let ebb1 = func.dfg.make_ebb(); + let ebb2 = func.dfg.make_ebb(); + let ebb0 = func.dfg.make_ebb(); + func.layout.append_ebb(ebb3); + func.layout.append_ebb(ebb1); + func.layout.append_ebb(ebb2); + func.layout.append_ebb(ebb0); + + let jmp_ebb3_ebb1 = make_inst::jump(&mut func, ebb1); + let br_ebb1_ebb0 = make_inst::branch(&mut func, ebb0); + let jmp_ebb1_ebb2 = make_inst::jump(&mut func, ebb2); + let jmp_ebb2_ebb0 = make_inst::jump(&mut func, ebb0); + + func.layout.append_inst(br_ebb1_ebb0, ebb1); + func.layout.append_inst(jmp_ebb1_ebb2, ebb1); + func.layout.append_inst(jmp_ebb2_ebb0, ebb2); + func.layout.append_inst(jmp_ebb3_ebb1, ebb3); + + let cfg = ControlFlowGraph::new(&func); + let dt = DominatorTree::new(&cfg); + + assert_eq!(func.layout.entry_block().unwrap(), ebb3); + assert_eq!(dt.len(), cfg.len()); + 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); + } +} diff --git a/cranelift/src/libcretonne/lib.rs b/cranelift/src/libcretonne/lib.rs index f81bfb5720..34151d187b 100644 --- a/cranelift/src/libcretonne/lib.rs +++ b/cranelift/src/libcretonne/lib.rs @@ -10,7 +10,7 @@ pub const VERSION: &'static str = env!("CARGO_PKG_VERSION"); pub mod ir; pub mod write; pub mod cfg; - +pub mod dominator_tree; pub mod entity_map; #[cfg(test)]pub mod test_utils; diff --git a/cranelift/src/libcretonne/tests/dominator_tree.rs b/cranelift/src/libcretonne/tests/dominator_tree.rs new file mode 100644 index 0000000000..6820acd152 --- /dev/null +++ b/cranelift/src/libcretonne/tests/dominator_tree.rs @@ -0,0 +1,60 @@ +extern crate cretonne; +extern crate cton_reader; + +use self::cton_reader::parser::Parser; +use self::cretonne::ir::entities::Ebb; +use self::cretonne::cfg::ControlFlowGraph; +use self::cretonne::dominator_tree::DominatorTree; + +fn test_dominator_tree(function_source: &str, idoms: Vec) { + let func = &Parser::parse(function_source).unwrap()[0]; + let cfg = ControlFlowGraph::new(&func); + let dtree = DominatorTree::new(&cfg); + assert_eq!(dtree.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); + } +} + +#[test] +fn basic() { + test_dominator_tree(" + function test(i32) { + ebb0(v0: i32): + jump ebb1 + ebb1: + brz v0, ebb3 + jump ebb2 + 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 + ebb1: + jump ebb3 + ebb2: + brz v0, ebb4 + jump ebb5 + ebb3: + jump ebb4 + ebb4: + brz v0, ebb3 + jump ebb5 + ebb5: + brz v0, ebb4 + return + } + ", vec![0, 0, 0, 0, 0, 0]); +} diff --git a/cranelift/src/libcretonne/tests/lib.rs b/cranelift/src/libcretonne/tests/lib.rs index 70d0709a9c..fcd2535269 100644 --- a/cranelift/src/libcretonne/tests/lib.rs +++ b/cranelift/src/libcretonne/tests/lib.rs @@ -1 +1,2 @@ pub mod cfg_traversal; +pub mod dominator_tree;