Fix handling of CFG triangles in compute_postorder.

For example, in `loops_one`, ebb3 is the bottom of a triangle, so
postorder should order it after the rest of the triangle.
This commit is contained in:
Dan Gohman
2017-11-07 16:57:22 -08:00
parent 849f090562
commit 2b6502ac6e
3 changed files with 24 additions and 36 deletions

View File

@@ -51,7 +51,7 @@ fn simple_traversal() {
trap user0
}
",
vec![0, 1, 3, 2, 4, 5],
vec![0, 2, 5, 4, 1, 3],
);
}
@@ -71,7 +71,7 @@ fn loops_one() {
return
}
",
vec![0, 1, 3, 2],
vec![0, 1, 2, 3],
);
}
@@ -98,7 +98,7 @@ fn loops_two() {
return
}
",
vec![0, 1, 2, 4, 3, 5],
vec![0, 2, 1, 3, 4, 5],
);
}
@@ -130,7 +130,7 @@ fn loops_three() {
return
}
",
vec![0, 1, 2, 4, 3, 6, 7, 5],
vec![0, 2, 1, 3, 4, 6, 7, 5],
);
}

View File

@@ -36,7 +36,7 @@ pub struct DominatorTree {
postorder: Vec<Ebb>,
// Scratch memory used by `compute_postorder()`.
stack: Vec<Ebb>,
stack: Vec<(Ebb, usize)>,
valid: bool,
}
@@ -255,39 +255,27 @@ impl DominatorTree {
// During this algorithm only, use `rpo_number` to hold the following state:
//
// 0: EBB never reached.
// 2: EBB has been pushed once, so it shouldn't be pushed again.
// 1: EBB has already been popped once, and should be added to the post-order next time.
const SEEN: u32 = 2;
const DONE: u32 = 1;
// 0: EBB is not yet on the stack.
// 1: EBB is on the stack or in postorder.
const SEEN: u32 = 1;
match func.layout.entry_block() {
Some(ebb) => {
self.stack.push((ebb, 0));
self.nodes[ebb].rpo_number = SEEN;
self.stack.push(ebb)
}
None => return,
}
while let Some(ebb) = self.stack.pop() {
match self.nodes[ebb].rpo_number {
// This is the first time we visit `ebb`, forming a pre-order.
SEEN => {
// Mark it as done and re-queue it to be visited after its children.
self.nodes[ebb].rpo_number = DONE;
self.stack.push(ebb);
for &succ in cfg.get_successors(ebb) {
// Only push children that haven't been seen before.
if self.nodes[succ].rpo_number == 0 {
self.nodes[succ].rpo_number = SEEN;
self.stack.push(succ);
}
}
while let Some((ebb, succ_index)) = self.stack.pop() {
if let Some(&succ) = cfg.get_successors(ebb).get(succ_index) {
self.stack.push((ebb, succ_index + 1));
if self.nodes[succ].rpo_number == 0 {
self.stack.push((succ, 0));
self.nodes[succ].rpo_number = SEEN;
}
// This is the second time we popped `ebb`, so all its children have been visited.
// This is the post-order.
DONE => self.postorder.push(ebb),
_ => panic!("Inconsistent stack rpo_number"),
} else {
self.postorder.push(ebb);
}
}
}
@@ -522,7 +510,7 @@ mod test {
Ordering::Less
);
assert_eq!(dt.cfg_postorder(), &[ebb2, ebb0, ebb1, ebb3]);
assert_eq!(dt.cfg_postorder(), &[ebb0, ebb2, ebb1, ebb3]);
}
#[test]

View File

@@ -326,16 +326,16 @@ mod test {
let loops = loop_analysis.loops().collect::<Vec<Loop>>();
assert_eq!(loops.len(), 3);
assert_eq!(loop_analysis.loop_header(loops[0]), ebb0);
assert_eq!(loop_analysis.loop_header(loops[1]), ebb1);
assert_eq!(loop_analysis.loop_header(loops[2]), ebb3);
assert_eq!(loop_analysis.loop_header(loops[1]), ebb3);
assert_eq!(loop_analysis.loop_header(loops[2]), ebb1);
assert_eq!(loop_analysis.loop_parent(loops[1]), Some(loops[0]));
assert_eq!(loop_analysis.loop_parent(loops[2]), Some(loops[0]));
assert_eq!(loop_analysis.loop_parent(loops[0]), None);
assert_eq!(loop_analysis.is_in_loop(ebb0, loops[0]), true);
assert_eq!(loop_analysis.is_in_loop(ebb1, loops[1]), true);
assert_eq!(loop_analysis.is_in_loop(ebb2, loops[1]), true);
assert_eq!(loop_analysis.is_in_loop(ebb3, loops[2]), true);
assert_eq!(loop_analysis.is_in_loop(ebb4, loops[2]), true);
assert_eq!(loop_analysis.is_in_loop(ebb3, loops[1]), true);
assert_eq!(loop_analysis.is_in_loop(ebb4, loops[1]), true);
assert_eq!(loop_analysis.is_in_loop(ebb1, loops[2]), true);
assert_eq!(loop_analysis.is_in_loop(ebb2, loops[2]), true);
assert_eq!(loop_analysis.is_in_loop(ebb5, loops[0]), true);
}
}