Use a bforest::Map for the predecessors in the CFG.
Like before, we store a redundant EBB with each predecessor instruction which allows invalidate_ebb_successors() to clean up the successor's predecessor lists even after instructions have been moved around in the layout.
This commit is contained in:
@@ -28,7 +28,6 @@ use ir::{Function, Inst, Ebb};
|
|||||||
use ir::instructions::BranchInfo;
|
use ir::instructions::BranchInfo;
|
||||||
use entity::EntityMap;
|
use entity::EntityMap;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice;
|
|
||||||
|
|
||||||
/// A basic block denoted by its enclosing Ebb and last instruction.
|
/// A basic block denoted by its enclosing Ebb and last instruction.
|
||||||
pub type BasicBlock = (Ebb, Inst);
|
pub type BasicBlock = (Ebb, Inst);
|
||||||
@@ -36,12 +35,23 @@ pub type BasicBlock = (Ebb, Inst);
|
|||||||
/// A container for the successors and predecessors of some Ebb.
|
/// A container for the successors and predecessors of some Ebb.
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
pub struct CFGNode {
|
pub struct CFGNode {
|
||||||
|
/// Instructions that can branch or jump to this EBB.
|
||||||
|
///
|
||||||
|
/// This maps branch instruction -> predecessor EBB which is redundant since the EBB containing
|
||||||
|
/// the branch instruction is available from the `layout.inst_ebb()` method. We store the
|
||||||
|
/// redundant information because:
|
||||||
|
///
|
||||||
|
/// 1. Many `pred_iter()` consumers want the EBB anyway, so it is handily available.
|
||||||
|
/// 2. The `invalidate_ebb_successors()` may be called *after* branches have been removed from
|
||||||
|
/// their EBB, but we still need to remove them form the old EBB predecessor map.
|
||||||
|
///
|
||||||
|
/// The redundant EBB stored here is always consistent with the CFG successor lists, even after
|
||||||
|
/// the IR has been edited.
|
||||||
|
pub predecessors: bforest::Map<Inst, Ebb, ()>,
|
||||||
|
|
||||||
/// Set of EBBs that are the targets of branches and jumps in this EBB.
|
/// Set of EBBs that are the targets of branches and jumps in this EBB.
|
||||||
/// The set is ordered by EBB number, indicated by the `()` comparator type.
|
/// The set is ordered by EBB number, indicated by the `()` comparator type.
|
||||||
pub successors: bforest::Set<Ebb, ()>,
|
pub successors: bforest::Set<Ebb, ()>,
|
||||||
|
|
||||||
/// Basic blocks that can branch or jump to this EBB.
|
|
||||||
pub predecessors: Vec<BasicBlock>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
|
/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
|
||||||
@@ -49,6 +59,7 @@ pub struct CFGNode {
|
|||||||
/// extended basic blocks.
|
/// extended basic blocks.
|
||||||
pub struct ControlFlowGraph {
|
pub struct ControlFlowGraph {
|
||||||
data: EntityMap<Ebb, CFGNode>,
|
data: EntityMap<Ebb, CFGNode>,
|
||||||
|
pred_forest: bforest::MapForest<Inst, Ebb, ()>,
|
||||||
succ_forest: bforest::SetForest<Ebb, ()>,
|
succ_forest: bforest::SetForest<Ebb, ()>,
|
||||||
valid: bool,
|
valid: bool,
|
||||||
}
|
}
|
||||||
@@ -59,6 +70,7 @@ impl ControlFlowGraph {
|
|||||||
Self {
|
Self {
|
||||||
data: EntityMap::new(),
|
data: EntityMap::new(),
|
||||||
valid: false,
|
valid: false,
|
||||||
|
pred_forest: bforest::MapForest::new(),
|
||||||
succ_forest: bforest::SetForest::new(),
|
succ_forest: bforest::SetForest::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,6 +78,7 @@ impl ControlFlowGraph {
|
|||||||
/// Clear all data structures in this control flow graph.
|
/// Clear all data structures in this control flow graph.
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
self.data.clear();
|
self.data.clear();
|
||||||
|
self.pred_forest.clear();
|
||||||
self.succ_forest.clear();
|
self.succ_forest.clear();
|
||||||
self.valid = false;
|
self.valid = false;
|
||||||
}
|
}
|
||||||
@@ -113,7 +126,10 @@ impl ControlFlowGraph {
|
|||||||
// our iteration over successors.
|
// our iteration over successors.
|
||||||
let mut successors = mem::replace(&mut self.data[ebb].successors, Default::default());
|
let mut successors = mem::replace(&mut self.data[ebb].successors, Default::default());
|
||||||
for succ in successors.iter(&self.succ_forest) {
|
for succ in successors.iter(&self.succ_forest) {
|
||||||
self.data[succ].predecessors.retain(|&(e, _)| e != ebb);
|
self.data[succ].predecessors.retain(
|
||||||
|
&mut self.pred_forest,
|
||||||
|
|_, &mut e| e != ebb,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
successors.clear(&mut self.succ_forest);
|
successors.clear(&mut self.succ_forest);
|
||||||
}
|
}
|
||||||
@@ -136,12 +152,17 @@ impl ControlFlowGraph {
|
|||||||
&mut self.succ_forest,
|
&mut self.succ_forest,
|
||||||
&(),
|
&(),
|
||||||
);
|
);
|
||||||
self.data[to].predecessors.push(from);
|
self.data[to].predecessors.insert(
|
||||||
|
from.1,
|
||||||
|
from.0,
|
||||||
|
&mut self.pred_forest,
|
||||||
|
&(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator over the CFG predecessors to `ebb`.
|
/// Get an iterator over the CFG predecessors to `ebb`.
|
||||||
pub fn pred_iter(&self, ebb: Ebb) -> PredIter {
|
pub fn pred_iter(&self, ebb: Ebb) -> PredIter {
|
||||||
PredIter(self.data[ebb].predecessors.iter())
|
PredIter(self.data[ebb].predecessors.iter(&self.pred_forest))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator over the CFG successors to `ebb`.
|
/// Get an iterator over the CFG successors to `ebb`.
|
||||||
@@ -163,13 +184,13 @@ impl ControlFlowGraph {
|
|||||||
/// An iterator over EBB predecessors. The iterator type is `BasicBlock`.
|
/// An iterator over EBB predecessors. The iterator type is `BasicBlock`.
|
||||||
///
|
///
|
||||||
/// Each predecessor is an instruction that branches to the EBB.
|
/// Each predecessor is an instruction that branches to the EBB.
|
||||||
pub struct PredIter<'a>(slice::Iter<'a, BasicBlock>);
|
pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Ebb, ()>);
|
||||||
|
|
||||||
impl<'a> Iterator for PredIter<'a> {
|
impl<'a> Iterator for PredIter<'a> {
|
||||||
type Item = BasicBlock;
|
type Item = BasicBlock;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<BasicBlock> {
|
fn next(&mut self) -> Option<BasicBlock> {
|
||||||
self.0.next().cloned()
|
self.0.next().map(|(i, e)| (e, i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user