Generalize rpo_cmp to handle all program points.

When comparing instructions in the same EBB, behave like the RPO visits
instructions in program order.

- Add a Layout::pp_ebb() method for convenience. It gets the EBB
  containing any program point.
- Add a conversion from ValueDef to ExpandedProgramPoint so it can be
  used with the rpo_cmp method.
This commit is contained in:
Jakob Stoklund Olesen
2017-06-12 13:53:12 -07:00
parent 706eef23d3
commit 4f9ff548bd
3 changed files with 48 additions and 5 deletions

View File

@@ -2,7 +2,7 @@
use entity_map::EntityMap;
use flowgraph::{ControlFlowGraph, BasicBlock};
use ir::{Ebb, Inst, Function, Layout, ProgramOrder};
use ir::{Ebb, Inst, Function, Layout, ProgramOrder, ExpandedProgramPoint};
use packed_option::PackedOption;
use std::cmp::Ordering;
@@ -66,11 +66,26 @@ impl DominatorTree {
self.nodes[ebb].idom.into()
}
/// Compare two EBBs relative to a reverse post-order traversal of the control-flow graph.
/// Compare two EBBs relative to the reverse post-order.
fn rpo_cmp_ebb(&self, a: Ebb, b: Ebb) -> Ordering {
self.nodes[a].rpo_number.cmp(&self.nodes[b].rpo_number)
}
/// Compare two program points relative to a reverse post-order traversal of the control-flow
/// graph.
///
/// Return `Ordering::Less` if `a` comes before `b` in the RPO.
pub fn rpo_cmp(&self, a: Ebb, b: Ebb) -> Ordering {
self.nodes[a].rpo_number.cmp(&self.nodes[b].rpo_number)
///
/// If `a` and `b` belong to the same EBB, compare their relative position in the EBB.
pub fn rpo_cmp<A, B>(&self, a: A, b: B, layout: &Layout) -> Ordering
where A: Into<ExpandedProgramPoint>,
B: Into<ExpandedProgramPoint>
{
let a = a.into();
let b = b.into();
self.rpo_cmp_ebb(layout.pp_ebb(a), layout.pp_ebb(b))
.then(layout.cmp(a, b))
}
/// Returns `true` if `a` dominates `b`.
@@ -118,7 +133,7 @@ impl DominatorTree {
layout: &Layout)
-> BasicBlock {
loop {
match self.rpo_cmp(a.0, b.0) {
match self.rpo_cmp_ebb(a.0, b.0) {
Ordering::Less => {
// `a` comes before `b` in the RPO. Move `b` up.
let idom = self.nodes[b.0].idom.expect("Unreachable basic block?");
@@ -349,6 +364,13 @@ mod test {
assert!(!dt.dominates(br_ebb1_ebb0, jmp_ebb3_ebb1, &func.layout));
assert!(dt.dominates(jmp_ebb3_ebb1, br_ebb1_ebb0, &func.layout));
assert_eq!(dt.rpo_cmp(ebb3, ebb3, &func.layout), Ordering::Equal);
assert_eq!(dt.rpo_cmp(ebb3, ebb1, &func.layout), Ordering::Less);
assert_eq!(dt.rpo_cmp(ebb3, jmp_ebb3_ebb1, &func.layout),
Ordering::Less);
assert_eq!(dt.rpo_cmp(jmp_ebb3_ebb1, jmp_ebb1_ebb2, &func.layout),
Ordering::Less);
assert_eq!(dt.cfg_postorder(), &[ebb2, ebb0, ebb1, ebb3]);
}
}

View File

@@ -412,6 +412,18 @@ impl Layout {
}
}
/// Get the EBB containing the program point `pp`. Panic if `pp` is not in the layout.
pub fn pp_ebb<PP>(&self, pp: PP) -> Ebb
where PP: Into<ExpandedProgramPoint>
{
match pp.into() {
ExpandedProgramPoint::Ebb(ebb) => ebb,
ExpandedProgramPoint::Inst(inst) => {
self.inst_ebb(inst).expect("Program point not in layout")
}
}
}
/// Append `inst` to the end of `ebb`.
pub fn append_inst(&mut self, inst: Inst, ebb: Ebb) {
assert_eq!(self.inst_ebb(inst), None);

View File

@@ -63,6 +63,15 @@ impl From<Ebb> for ExpandedProgramPoint {
}
}
impl From<ValueDef> for ExpandedProgramPoint {
fn from(def: ValueDef) -> ExpandedProgramPoint {
match def {
ValueDef::Res(inst, _) => inst.into(),
ValueDef::Arg(ebb, _) => ebb.into(),
}
}
}
impl From<ProgramPoint> for ExpandedProgramPoint {
fn from(pp: ProgramPoint) -> ExpandedProgramPoint {
if pp.0 & 1 == 0 {