make postorder_ebbs into actually reverse_postorder_ebbs.

This is a more accurate description. Further return the ebbs in a
btreemap so that the index of each Ebb (its order of visitation) is
quick to lookup.
This commit is contained in:
Morgan Phillips
2016-07-25 00:41:34 -07:00
parent 8d93fe9685
commit aa730ec2c4

View File

@@ -24,8 +24,9 @@
use ir::Function;
use ir::entities::{Inst, Ebb};
use ir::instructions::BranchInfo;
use ir::instructions::InstructionData;
use entity_map::EntityMap;
use std::collections::{HashSet, BTreeMap};
/// A basic block denoted by its enclosing Ebb and last instruction.
pub type BasicBlock = (Ebb, Inst);
@@ -51,6 +52,7 @@ impl CFGNode {
/// extended basic blocks.
#[derive(Debug)]
pub struct ControlFlowGraph {
entry_block: Option<Ebb>,
data: EntityMap<Ebb, CFGNode>,
}
@@ -58,7 +60,11 @@ impl ControlFlowGraph {
/// During initialization mappings will be generated for any existing
/// blocks within the CFG's associated function.
pub fn new(func: &Function) -> ControlFlowGraph {
let mut cfg = ControlFlowGraph { data: EntityMap::new() };
let mut cfg = ControlFlowGraph {
data: EntityMap::new(),
entry_block: func.layout.entry_block(),
};
// Even ebbs without predecessors should show up in the CFG, albeit
// with no entires.
@@ -68,18 +74,16 @@ impl ControlFlowGraph {
for ebb in &func.layout {
for inst in func.layout.ebb_insts(ebb) {
match func.dfg[inst].analyze_branch() {
BranchInfo::SingleDest(dest, _) => {
cfg.add_successor(ebb, dest);
cfg.add_predecessor(dest, (ebb, inst));
match func.dfg[inst] {
InstructionData::Branch { ty: _, opcode: _, ref data } => {
cfg.add_successor(ebb, data.destination);
cfg.add_predecessor(data.destination, (ebb, inst));
}
BranchInfo::Table(jt) => {
for (_, dest) in func.jump_tables[jt].entries() {
cfg.add_successor(ebb, dest);
cfg.add_predecessor(dest, (ebb, inst));
InstructionData::Jump { ty: _, opcode: _, ref data } => {
cfg.add_successor(ebb, data.destination);
cfg.add_predecessor(data.destination, (ebb, inst));
}
}
BranchInfo::NotABranch => {}
_ => (),
}
}
}
@@ -106,19 +110,30 @@ impl ControlFlowGraph {
&self.data[ebb].successors
}
pub fn postorder_ebbs(&self, entry: Ebb) -> Vec<Ebb> {
let mut stack_a = vec![entry];
let mut stack_b = Vec::new();
/// Return ebbs in reverse postorder along with a mapping of
/// the ebb to its order of visitation.
pub fn reverse_postorder_ebbs(&self) -> BTreeMap<Ebb, usize> {
let entry_block = match self.entry_block {
None => {
return BTreeMap::new();
}
Some(eb) => eb,
};
let mut seen = HashSet::new();
let mut stack_a = vec![entry_block];
let mut finished = BTreeMap::new();
while stack_a.len() > 0 {
let cur = stack_a.pop().unwrap();
for child in &self.data[cur].successors {
if *child != cur && !stack_a.contains(child) {
if *child != cur && !seen.contains(&child) {
seen.insert(child);
stack_a.push(child.clone());
}
}
stack_b.push(cur);
let index = finished.len();
finished.insert(cur, index);
}
stack_b
finished
}
pub fn len(&self) -> usize {
@@ -281,12 +296,15 @@ mod tests {
func.layout.append_inst(jmp_ebb2_ebb5, ebb2);
let cfg = ControlFlowGraph::new(&func);
assert_eq!(cfg.postorder_ebbs(func.layout.entry_block().unwrap()),
vec![ebb0, ebb2, ebb5, ebb4, ebb1, ebb3]);
let mut postorder = vec![ebb3, ebb1, ebb4, ebb5, ebb2, ebb0];
postorder.reverse();
for (ebb, key) in cfg.reverse_postorder_ebbs() {
assert_eq!(ebb, postorder[key]);
}
}
#[test]
fn loop_edge() {
fn loops_one() {
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
let ebb1 = func.dfg.make_ebb();
@@ -308,7 +326,55 @@ mod tests {
func.layout.append_inst(jmp_ebb2_ebb3, ebb2);
let cfg = ControlFlowGraph::new(&func);
assert_eq!(cfg.postorder_ebbs(func.layout.entry_block().unwrap()),
vec![ebb0, ebb1, ebb2, ebb3]);
let mut postorder = vec![ebb3, ebb2, ebb1, ebb0];
postorder.reverse();
for (ebb, key) in cfg.reverse_postorder_ebbs() {
assert_eq!(ebb, postorder[key]);
}
}
#[test]
fn loops_two() {
let mut func = Function::new();
let ebb0 = func.dfg.make_ebb();
let ebb1 = func.dfg.make_ebb();
let ebb2 = func.dfg.make_ebb();
let ebb3 = func.dfg.make_ebb();
let ebb4 = func.dfg.make_ebb();
let ebb5 = func.dfg.make_ebb();
func.layout.append_ebb(ebb0);
func.layout.append_ebb(ebb1);
func.layout.append_ebb(ebb2);
func.layout.append_ebb(ebb3);
func.layout.append_ebb(ebb4);
func.layout.append_ebb(ebb5);
let jmp_ebb0_ebb1 = make_inst::jump(&mut func, ebb1);
let jmp_ebb0_ebb2 = make_inst::jump(&mut func, ebb2);
let jmp_ebb1_ebb3 = make_inst::jump(&mut func, ebb3);
let br_ebb2_ebb4 = make_inst::jump(&mut func, ebb4);
let jmp_ebb2_ebb5 = make_inst::jump(&mut func, ebb5);
let jmp_ebb3_ebb4 = make_inst::jump(&mut func, ebb4);
let br_ebb4_ebb3 = make_inst::branch(&mut func, ebb3);
let jmp_ebb4_ebb5 = make_inst::jump(&mut func, ebb5);
let jmp_ebb5_ebb4 = make_inst::jump(&mut func, ebb4);
func.layout.append_inst(jmp_ebb0_ebb1, ebb0);
func.layout.append_inst(jmp_ebb0_ebb2, ebb0);
func.layout.append_inst(jmp_ebb1_ebb3, ebb1);
func.layout.append_inst(br_ebb2_ebb4, ebb2);
func.layout.append_inst(jmp_ebb2_ebb5, ebb2);
func.layout.append_inst(jmp_ebb3_ebb4, ebb3);
func.layout.append_inst(br_ebb4_ebb3, ebb4);
func.layout.append_inst(jmp_ebb4_ebb5, ebb4);
func.layout.append_inst(jmp_ebb5_ebb4, ebb5);
let cfg = ControlFlowGraph::new(&func);
let mut postorder = vec![ebb1, ebb3, ebb4, ebb5, ebb2, ebb0];
postorder.reverse();
for (ebb, key) in cfg.reverse_postorder_ebbs() {
assert_eq!(ebb, postorder[key]);
}
}
}