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 trap user0
} }
", ",
vec![0, 1, 3, 2, 4, 5], vec![0, 2, 5, 4, 1, 3],
); );
} }
@@ -71,7 +71,7 @@ fn loops_one() {
return return
} }
", ",
vec![0, 1, 3, 2], vec![0, 1, 2, 3],
); );
} }
@@ -98,7 +98,7 @@ fn loops_two() {
return return
} }
", ",
vec![0, 1, 2, 4, 3, 5], vec![0, 2, 1, 3, 4, 5],
); );
} }
@@ -130,7 +130,7 @@ fn loops_three() {
return 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>, postorder: Vec<Ebb>,
// Scratch memory used by `compute_postorder()`. // Scratch memory used by `compute_postorder()`.
stack: Vec<Ebb>, stack: Vec<(Ebb, usize)>,
valid: bool, valid: bool,
} }
@@ -255,39 +255,27 @@ impl DominatorTree {
// During this algorithm only, use `rpo_number` to hold the following state: // During this algorithm only, use `rpo_number` to hold the following state:
// //
// 0: EBB never reached. // 0: EBB is not yet on the stack.
// 2: EBB has been pushed once, so it shouldn't be pushed again. // 1: EBB is on the stack or in postorder.
// 1: EBB has already been popped once, and should be added to the post-order next time. const SEEN: u32 = 1;
const SEEN: u32 = 2;
const DONE: u32 = 1;
match func.layout.entry_block() { match func.layout.entry_block() {
Some(ebb) => { Some(ebb) => {
self.stack.push((ebb, 0));
self.nodes[ebb].rpo_number = SEEN; self.nodes[ebb].rpo_number = SEEN;
self.stack.push(ebb)
} }
None => return, None => return,
} }
while let Some(ebb) = self.stack.pop() { while let Some((ebb, succ_index)) = self.stack.pop() {
match self.nodes[ebb].rpo_number { if let Some(&succ) = cfg.get_successors(ebb).get(succ_index) {
// This is the first time we visit `ebb`, forming a pre-order. self.stack.push((ebb, succ_index + 1));
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 { if self.nodes[succ].rpo_number == 0 {
self.stack.push((succ, 0));
self.nodes[succ].rpo_number = SEEN; self.nodes[succ].rpo_number = SEEN;
self.stack.push(succ);
} }
} } else {
} self.postorder.push(ebb);
// 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"),
} }
} }
} }
@@ -522,7 +510,7 @@ mod test {
Ordering::Less Ordering::Less
); );
assert_eq!(dt.cfg_postorder(), &[ebb2, ebb0, ebb1, ebb3]); assert_eq!(dt.cfg_postorder(), &[ebb0, ebb2, ebb1, ebb3]);
} }
#[test] #[test]

View File

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