Use EntityMap instead of BTreeMap

This commit is contained in:
Morgan Phillips
2016-07-21 12:08:02 -07:00
parent 89ba9626c7
commit 2caa802f50
2 changed files with 53 additions and 25 deletions

View File

@@ -1,5 +1,5 @@
//! A control flow graph represented as mappings of extended basic blocks to their predecessors. //! A control flow graph represented as mappings of extended basic blocks to their predecessors.
//! Predecessors are denoted by tuples of EBB and branch/jump instructions. Each predecessor //! BasicBlocks are denoted by tuples of EBB and branch/jump instructions. Each predecessor
//! tuple corresponds to the end of a basic block. //! tuple corresponds to the end of a basic block.
//! //!
//! ```c //! ```c
@@ -23,20 +23,21 @@
use repr::Function; use repr::Function;
use repr::entities::{Inst, Ebb}; use repr::entities::{Inst, Ebb};
use repr::instructions::InstructionData; use repr::instructions::InstructionData;
use std::collections::{BTreeSet, BTreeMap, btree_map}; use entity_map::EntityMap;
use std::collections::BTreeSet;
/// A basic block denoted by its enclosing Ebb and last instruction. /// A basic block denoted by its enclosing Ebb and last instruction.
pub type Predecessor = (Ebb, Inst); pub type BasicBlock = (Ebb, Inst);
/// Storing predecessors in a BTreeSet ensures that their ordering is /// Storing predecessors in a BTreeSet ensures that their ordering is
/// stable with no duplicates. /// stable with no duplicates.
pub type PredecessorSet = BTreeSet<Predecessor>; pub type BasicBlockSet = BTreeSet<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
/// where predecessors are basic blocks. /// where predecessors are basic blocks.
#[derive(Debug)] #[derive(Debug)]
pub struct ControlFlowGraph { pub struct ControlFlowGraph {
data: BTreeMap<Ebb, PredecessorSet>, data: EntityMap<Ebb, BasicBlockSet>,
} }
impl ControlFlowGraph { impl ControlFlowGraph {
@@ -44,12 +45,12 @@ impl ControlFlowGraph {
/// blocks within the CFG's associated function. Basic sanity checks will /// blocks within the CFG's associated function. Basic sanity checks will
/// also be performed to ensure that the blocks are well formed. /// also be performed to ensure that the blocks are well formed.
pub fn new(func: &Function) -> ControlFlowGraph { pub fn new(func: &Function) -> ControlFlowGraph {
let mut cfg = ControlFlowGraph { data: BTreeMap::new() }; let mut cfg = ControlFlowGraph { data: EntityMap::new() };
// Even ebbs without predecessors should show up in the CFG, albeit // Even ebbs without predecessors should show up in the CFG, albeit
// with no entires. // with no entires.
for ebb in &func.layout { for _ in &func.layout {
cfg.init_ebb(ebb); cfg.push_ebb();
} }
for ebb in &func.layout { for ebb in &func.layout {
@@ -70,25 +71,48 @@ impl ControlFlowGraph {
cfg cfg
} }
/// Initializes a predecessor set for some ebb. If an ebb already has an pub fn push_ebb(&mut self) {
/// entry it will be clobbered. self.data.push(BTreeSet::new());
pub fn init_ebb(&mut self, ebb: Ebb) -> &mut PredecessorSet {
self.data.insert(ebb, BTreeSet::new());
self.data.get_mut(&ebb).unwrap()
} }
pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: Predecessor) { pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: BasicBlock) {
self.data.get_mut(&ebb).unwrap().insert(predecessor); self.data[ebb].insert(predecessor);
} }
/// Returns all of the predecessors for some ebb, if it has an entry. /// Returns all of the predecessors for some ebb, if it has an entry.
pub fn get_predecessors(&self, ebb: Ebb) -> Option<&PredecessorSet> { pub fn get_predecessors(&self, ebb: Ebb) -> &BasicBlockSet {
self.data.get(&ebb) &self.data[ebb]
} }
/// An iterator over all of the ebb to predecessor mappings in the CFG. pub fn len(&self) -> usize {
pub fn iter<'a>(&'a self) -> btree_map::Iter<'a, Ebb, PredecessorSet> { self.data.len()
self.data.iter() }
pub fn iter(&self) -> CFGIter {
CFGIter {
cur: 0,
cfg: &self,
}
}
}
pub struct CFGIter<'a> {
cfg: &'a ControlFlowGraph,
cur: usize,
}
impl<'a> Iterator for CFGIter<'a> {
type Item = (Ebb, &'a BasicBlockSet);
fn next(&mut self) -> Option<Self::Item> {
if self.cur < self.cfg.len() {
let ebb = Ebb::with_number(self.cur as u32).unwrap();
let bbs = self.cfg.get_predecessors(ebb);
self.cur += 1;
Some((ebb, bbs))
} else {
None
}
} }
} }
@@ -122,7 +146,7 @@ mod tests {
let mut fun_ebbs = func.layout.ebbs(); let mut fun_ebbs = func.layout.ebbs();
for (ebb, predecessors) in nodes { for (ebb, predecessors) in nodes {
assert_eq!(*ebb, fun_ebbs.next().unwrap()); assert_eq!(ebb, fun_ebbs.next().unwrap());
assert_eq!(predecessors.len(), 0); assert_eq!(predecessors.len(), 0);
} }
} }
@@ -150,9 +174,9 @@ mod tests {
func.layout.append_inst(jmp_ebb1_ebb2, ebb1); func.layout.append_inst(jmp_ebb1_ebb2, ebb1);
let cfg = ControlFlowGraph::new(&func); let cfg = ControlFlowGraph::new(&func);
let ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap(); let ebb0_predecessors = cfg.get_predecessors(ebb0);
let ebb1_predecessors = cfg.get_predecessors(ebb1).unwrap(); let ebb1_predecessors = cfg.get_predecessors(ebb1);
let ebb2_predecessors = cfg.get_predecessors(ebb2).unwrap(); let ebb2_predecessors = cfg.get_predecessors(ebb2);
assert_eq!(ebb0_predecessors.len(), 0); assert_eq!(ebb0_predecessors.len(), 0);
assert_eq!(ebb1_predecessors.len(), 2); assert_eq!(ebb1_predecessors.len(), 2);
assert_eq!(ebb2_predecessors.len(), 2); assert_eq!(ebb2_predecessors.len(), 2);
@@ -162,5 +186,4 @@ mod tests {
assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true); assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true); assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);
} }
} }

View File

@@ -46,6 +46,7 @@ pub trait EntityRef: Copy + Eq {
/// A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The /// A *secondary* `EntityMap` contains additional data about entities kept in a primary map. The
/// values need to implement `Clone + Default` traits so the map can be grown with `ensure`. /// values need to implement `Clone + Default` traits so the map can be grown with `ensure`.
/// ///
#[derive(Debug)]
pub struct EntityMap<K, V> pub struct EntityMap<K, V>
where K: EntityRef where K: EntityRef
{ {
@@ -76,6 +77,10 @@ impl<K, V> EntityMap<K, V>
self.elems.push(v); self.elems.push(v);
k k
} }
pub fn len(&self) -> usize {
self.elems.len()
}
} }
/// Additional methods for value types that implement `Clone` and `Default`. /// Additional methods for value types that implement `Clone` and `Default`.