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:
@@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user