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 entity_map::EntityMap;
|
||||||
use flowgraph::{ControlFlowGraph, BasicBlock};
|
use flowgraph::{ControlFlowGraph, BasicBlock};
|
||||||
use ir::{Ebb, Inst, Function, Layout, ProgramOrder};
|
use ir::{Ebb, Inst, Function, Layout, ProgramOrder, ExpandedProgramPoint};
|
||||||
use packed_option::PackedOption;
|
use packed_option::PackedOption;
|
||||||
|
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
@@ -66,11 +66,26 @@ impl DominatorTree {
|
|||||||
self.nodes[ebb].idom.into()
|
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.
|
/// 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`.
|
/// Returns `true` if `a` dominates `b`.
|
||||||
@@ -118,7 +133,7 @@ impl DominatorTree {
|
|||||||
layout: &Layout)
|
layout: &Layout)
|
||||||
-> BasicBlock {
|
-> BasicBlock {
|
||||||
loop {
|
loop {
|
||||||
match self.rpo_cmp(a.0, b.0) {
|
match self.rpo_cmp_ebb(a.0, b.0) {
|
||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
// `a` comes before `b` in the RPO. Move `b` up.
|
// `a` comes before `b` in the RPO. Move `b` up.
|
||||||
let idom = self.nodes[b.0].idom.expect("Unreachable basic block?");
|
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(br_ebb1_ebb0, jmp_ebb3_ebb1, &func.layout));
|
||||||
assert!(dt.dominates(jmp_ebb3_ebb1, br_ebb1_ebb0, &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]);
|
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`.
|
/// Append `inst` to the end of `ebb`.
|
||||||
pub fn append_inst(&mut self, inst: Inst, ebb: Ebb) {
|
pub fn append_inst(&mut self, inst: Inst, ebb: Ebb) {
|
||||||
assert_eq!(self.inst_ebb(inst), None);
|
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 {
|
impl From<ProgramPoint> for ExpandedProgramPoint {
|
||||||
fn from(pp: ProgramPoint) -> ExpandedProgramPoint {
|
fn from(pp: ProgramPoint) -> ExpandedProgramPoint {
|
||||||
if pp.0 & 1 == 0 {
|
if pp.0 & 1 == 0 {
|
||||||
|
|||||||
Reference in New Issue
Block a user