Mass rename Ebb and relatives to Block (#1365)
* Manually rename BasicBlock to BlockPredecessor BasicBlock is a pair of (Ebb, Inst) that is used to represent the basic block subcomponent of an Ebb that is a predecessor to an Ebb. Eventually we will be able to remove this struct, but for now it makes sense to give it a non-conflicting name so that we can start to transition Ebb to represent a basic block. I have not updated any comments that refer to BasicBlock, as eventually we will remove BlockPredecessor and replace with Block, which is a basic block, so the comments will become correct. * Manually rename SSABuilder block types to avoid conflict SSABuilder has its own Block and BlockData types. These along with associated identifier will cause conflicts in a later commit, so they are renamed to be more verbose here. * Automatically rename 'Ebb' to 'Block' in *.rs * Automatically rename 'EBB' to 'block' in *.rs * Automatically rename 'ebb' to 'block' in *.rs * Automatically rename 'extended basic block' to 'basic block' in *.rs * Automatically rename 'an basic block' to 'a basic block' in *.rs * Manually update comment for `Block` `Block`'s wikipedia article required an update. * Automatically rename 'an `Block`' to 'a `Block`' in *.rs * Automatically rename 'extended_basic_block' to 'basic_block' in *.rs * Automatically rename 'ebb' to 'block' in *.clif * Manually rename clif constant that contains 'ebb' as substring to avoid conflict * Automatically rename filecheck uses of 'EBB' to 'BB' 'regex: EBB' -> 'regex: BB' '$EBB' -> '$BB' * Automatically rename 'EBB' 'Ebb' to 'block' in *.clif * Automatically rename 'an block' to 'a block' in *.clif * Fix broken testcase when function name length increases Test function names are limited to 16 characters. This causes the new longer name to be truncated and fail a filecheck test. An outdated comment was also fixed.
This commit is contained in:
@@ -1,80 +1,80 @@
|
||||
//! A control flow graph represented as mappings of extended basic blocks to their predecessors
|
||||
//! A control flow graph represented as mappings of basic blocks to their predecessors
|
||||
//! and successors.
|
||||
//!
|
||||
//! Successors are represented as extended basic blocks while predecessors are represented by basic
|
||||
//! blocks. Basic blocks are denoted by tuples of EBB and branch/jump instructions. Each
|
||||
//! Successors are represented as basic blocks while predecessors are represented by basic
|
||||
//! blocks. Basic blocks are denoted by tuples of block and branch/jump instructions. Each
|
||||
//! predecessor tuple corresponds to the end of a basic block.
|
||||
//!
|
||||
//! ```c
|
||||
//! Ebb0:
|
||||
//! Block0:
|
||||
//! ... ; beginning of basic block
|
||||
//!
|
||||
//! ...
|
||||
//!
|
||||
//! brz vx, Ebb1 ; end of basic block
|
||||
//! brz vx, Block1 ; end of basic block
|
||||
//!
|
||||
//! ... ; beginning of basic block
|
||||
//!
|
||||
//! ...
|
||||
//!
|
||||
//! jmp Ebb2 ; end of basic block
|
||||
//! jmp Block2 ; end of basic block
|
||||
//! ```
|
||||
//!
|
||||
//! Here `Ebb1` and `Ebb2` would each have a single predecessor denoted as `(Ebb0, brz)`
|
||||
//! and `(Ebb0, jmp Ebb2)` respectively.
|
||||
//! Here `Block1` and `Block2` would each have a single predecessor denoted as `(Block0, brz)`
|
||||
//! and `(Block0, jmp Block2)` respectively.
|
||||
|
||||
use crate::bforest;
|
||||
use crate::entity::SecondaryMap;
|
||||
use crate::ir::instructions::BranchInfo;
|
||||
use crate::ir::{Ebb, Function, Inst};
|
||||
use crate::ir::{Block, Function, Inst};
|
||||
use crate::timing;
|
||||
use core::mem;
|
||||
|
||||
/// A basic block denoted by its enclosing Ebb and last instruction.
|
||||
/// A basic block denoted by its enclosing Block and last instruction.
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub struct BasicBlock {
|
||||
/// Enclosing Ebb key.
|
||||
pub ebb: Ebb,
|
||||
pub struct BlockPredecessor {
|
||||
/// Enclosing Block key.
|
||||
pub block: Block,
|
||||
/// Last instruction in the basic block.
|
||||
pub inst: Inst,
|
||||
}
|
||||
|
||||
impl BasicBlock {
|
||||
/// Convenient method to construct new BasicBlock.
|
||||
pub fn new(ebb: Ebb, inst: Inst) -> Self {
|
||||
Self { ebb, inst }
|
||||
impl BlockPredecessor {
|
||||
/// Convenient method to construct new BlockPredecessor.
|
||||
pub fn new(block: Block, inst: Inst) -> Self {
|
||||
Self { block, inst }
|
||||
}
|
||||
}
|
||||
|
||||
/// A container for the successors and predecessors of some Ebb.
|
||||
/// A container for the successors and predecessors of some Block.
|
||||
#[derive(Clone, Default)]
|
||||
struct CFGNode {
|
||||
/// Instructions that can branch or jump to this EBB.
|
||||
/// Instructions that can branch or jump to this block.
|
||||
///
|
||||
/// 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
|
||||
/// This maps branch instruction -> predecessor block which is redundant since the block containing
|
||||
/// the branch instruction is available from the `layout.inst_block()` 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.
|
||||
/// 1. Many `pred_iter()` consumers want the block anyway, so it is handily available.
|
||||
/// 2. The `invalidate_block_successors()` may be called *after* branches have been removed from
|
||||
/// their block, but we still need to remove them form the old block predecessor map.
|
||||
///
|
||||
/// The redundant EBB stored here is always consistent with the CFG successor lists, even after
|
||||
/// The redundant block stored here is always consistent with the CFG successor lists, even after
|
||||
/// the IR has been edited.
|
||||
pub predecessors: bforest::Map<Inst, Ebb>,
|
||||
pub predecessors: bforest::Map<Inst, Block>,
|
||||
|
||||
/// 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.
|
||||
pub successors: bforest::Set<Ebb>,
|
||||
/// Set of blocks that are the targets of branches and jumps in this block.
|
||||
/// The set is ordered by block number, indicated by the `()` comparator type.
|
||||
pub successors: bforest::Set<Block>,
|
||||
}
|
||||
|
||||
/// The Control Flow Graph maintains a mapping of ebbs to their predecessors
|
||||
/// The Control Flow Graph maintains a mapping of blocks to their predecessors
|
||||
/// and successors where predecessors are basic blocks and successors are
|
||||
/// extended basic blocks.
|
||||
/// basic blocks.
|
||||
pub struct ControlFlowGraph {
|
||||
data: SecondaryMap<Ebb, CFGNode>,
|
||||
pred_forest: bforest::MapForest<Inst, Ebb>,
|
||||
succ_forest: bforest::SetForest<Ebb>,
|
||||
data: SecondaryMap<Block, CFGNode>,
|
||||
pred_forest: bforest::MapForest<Inst, Block>,
|
||||
succ_forest: bforest::SetForest<Block>,
|
||||
valid: bool,
|
||||
}
|
||||
|
||||
@@ -110,27 +110,27 @@ impl ControlFlowGraph {
|
||||
pub fn compute(&mut self, func: &Function) {
|
||||
let _tt = timing::flowgraph();
|
||||
self.clear();
|
||||
self.data.resize(func.dfg.num_ebbs());
|
||||
self.data.resize(func.dfg.num_blocks());
|
||||
|
||||
for ebb in &func.layout {
|
||||
self.compute_ebb(func, ebb);
|
||||
for block in &func.layout {
|
||||
self.compute_block(func, block);
|
||||
}
|
||||
|
||||
self.valid = true;
|
||||
}
|
||||
|
||||
fn compute_ebb(&mut self, func: &Function, ebb: Ebb) {
|
||||
for inst in func.layout.ebb_insts(ebb) {
|
||||
fn compute_block(&mut self, func: &Function, block: Block) {
|
||||
for inst in func.layout.block_insts(block) {
|
||||
match func.dfg.analyze_branch(inst) {
|
||||
BranchInfo::SingleDest(dest, _) => {
|
||||
self.add_edge(ebb, inst, dest);
|
||||
self.add_edge(block, inst, dest);
|
||||
}
|
||||
BranchInfo::Table(jt, dest) => {
|
||||
if let Some(dest) = dest {
|
||||
self.add_edge(ebb, inst, dest);
|
||||
self.add_edge(block, inst, dest);
|
||||
}
|
||||
for dest in func.jump_tables[jt].iter() {
|
||||
self.add_edge(ebb, inst, *dest);
|
||||
self.add_edge(block, inst, *dest);
|
||||
}
|
||||
}
|
||||
BranchInfo::NotABranch => {}
|
||||
@@ -138,32 +138,32 @@ impl ControlFlowGraph {
|
||||
}
|
||||
}
|
||||
|
||||
fn invalidate_ebb_successors(&mut self, ebb: Ebb) {
|
||||
fn invalidate_block_successors(&mut self, block: Block) {
|
||||
// Temporarily take ownership because we need mutable access to self.data inside the loop.
|
||||
// Unfortunately borrowck cannot see that our mut accesses to predecessors don't alias
|
||||
// our iteration over successors.
|
||||
let mut successors = mem::replace(&mut self.data[ebb].successors, Default::default());
|
||||
let mut successors = mem::replace(&mut self.data[block].successors, Default::default());
|
||||
for succ in successors.iter(&self.succ_forest) {
|
||||
self.data[succ]
|
||||
.predecessors
|
||||
.retain(&mut self.pred_forest, |_, &mut e| e != ebb);
|
||||
.retain(&mut self.pred_forest, |_, &mut e| e != block);
|
||||
}
|
||||
successors.clear(&mut self.succ_forest);
|
||||
}
|
||||
|
||||
/// Recompute the control flow graph of `ebb`.
|
||||
/// Recompute the control flow graph of `block`.
|
||||
///
|
||||
/// This is for use after modifying instructions within a specific EBB. It recomputes all edges
|
||||
/// from `ebb` while leaving edges to `ebb` intact. Its functionality a subset of that of the
|
||||
/// This is for use after modifying instructions within a specific block. It recomputes all edges
|
||||
/// from `block` while leaving edges to `block` intact. Its functionality a subset of that of the
|
||||
/// more expensive `compute`, and should be used when we know we don't need to recompute the CFG
|
||||
/// from scratch, but rather that our changes have been restricted to specific EBBs.
|
||||
pub fn recompute_ebb(&mut self, func: &Function, ebb: Ebb) {
|
||||
/// from scratch, but rather that our changes have been restricted to specific blocks.
|
||||
pub fn recompute_block(&mut self, func: &Function, block: Block) {
|
||||
debug_assert!(self.is_valid());
|
||||
self.invalidate_ebb_successors(ebb);
|
||||
self.compute_ebb(func, ebb);
|
||||
self.invalidate_block_successors(block);
|
||||
self.compute_block(func, block);
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, from: Ebb, from_inst: Inst, to: Ebb) {
|
||||
fn add_edge(&mut self, from: Block, from_inst: Inst, to: Block) {
|
||||
self.data[from]
|
||||
.successors
|
||||
.insert(to, &mut self.succ_forest, &());
|
||||
@@ -172,15 +172,15 @@ impl ControlFlowGraph {
|
||||
.insert(from_inst, from, &mut self.pred_forest, &());
|
||||
}
|
||||
|
||||
/// Get an iterator over the CFG predecessors to `ebb`.
|
||||
pub fn pred_iter(&self, ebb: Ebb) -> PredIter {
|
||||
PredIter(self.data[ebb].predecessors.iter(&self.pred_forest))
|
||||
/// Get an iterator over the CFG predecessors to `block`.
|
||||
pub fn pred_iter(&self, block: Block) -> PredIter {
|
||||
PredIter(self.data[block].predecessors.iter(&self.pred_forest))
|
||||
}
|
||||
|
||||
/// Get an iterator over the CFG successors to `ebb`.
|
||||
pub fn succ_iter(&self, ebb: Ebb) -> SuccIter {
|
||||
/// Get an iterator over the CFG successors to `block`.
|
||||
pub fn succ_iter(&self, block: Block) -> SuccIter {
|
||||
debug_assert!(self.is_valid());
|
||||
self.data[ebb].successors.iter(&self.succ_forest)
|
||||
self.data[block].successors.iter(&self.succ_forest)
|
||||
}
|
||||
|
||||
/// Check if the CFG is in a valid state.
|
||||
@@ -193,21 +193,21 @@ impl ControlFlowGraph {
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over EBB predecessors. The iterator type is `BasicBlock`.
|
||||
/// An iterator over block predecessors. The iterator type is `BlockPredecessor`.
|
||||
///
|
||||
/// Each predecessor is an instruction that branches to the EBB.
|
||||
pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Ebb>);
|
||||
/// Each predecessor is an instruction that branches to the block.
|
||||
pub struct PredIter<'a>(bforest::MapIter<'a, Inst, Block>);
|
||||
|
||||
impl<'a> Iterator for PredIter<'a> {
|
||||
type Item = BasicBlock;
|
||||
type Item = BlockPredecessor;
|
||||
|
||||
fn next(&mut self) -> Option<BasicBlock> {
|
||||
self.0.next().map(|(i, e)| BasicBlock::new(e, i))
|
||||
fn next(&mut self) -> Option<BlockPredecessor> {
|
||||
self.0.next().map(|(i, e)| BlockPredecessor::new(e, i))
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over EBB successors. The iterator type is `Ebb`.
|
||||
pub type SuccIter<'a> = bforest::SetIter<'a, Ebb>;
|
||||
/// An iterator over block successors. The iterator type is `Block`.
|
||||
pub type SuccIter<'a> = bforest::SetIter<'a, Block>;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -225,126 +225,126 @@ mod tests {
|
||||
#[test]
|
||||
fn no_predecessors() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let ebb1 = func.dfg.make_ebb();
|
||||
let ebb2 = func.dfg.make_ebb();
|
||||
func.layout.append_ebb(ebb0);
|
||||
func.layout.append_ebb(ebb1);
|
||||
func.layout.append_ebb(ebb2);
|
||||
let block0 = func.dfg.make_block();
|
||||
let block1 = func.dfg.make_block();
|
||||
let block2 = func.dfg.make_block();
|
||||
func.layout.append_block(block0);
|
||||
func.layout.append_block(block1);
|
||||
func.layout.append_block(block2);
|
||||
|
||||
let cfg = ControlFlowGraph::with_function(&func);
|
||||
|
||||
let mut fun_ebbs = func.layout.ebbs();
|
||||
for ebb in func.layout.ebbs() {
|
||||
assert_eq!(ebb, fun_ebbs.next().unwrap());
|
||||
assert_eq!(cfg.pred_iter(ebb).count(), 0);
|
||||
assert_eq!(cfg.succ_iter(ebb).count(), 0);
|
||||
let mut fun_blocks = func.layout.blocks();
|
||||
for block in func.layout.blocks() {
|
||||
assert_eq!(block, fun_blocks.next().unwrap());
|
||||
assert_eq!(cfg.pred_iter(block).count(), 0);
|
||||
assert_eq!(cfg.succ_iter(block).count(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branches_and_jumps() {
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.dfg.make_ebb();
|
||||
let cond = func.dfg.append_ebb_param(ebb0, types::I32);
|
||||
let ebb1 = func.dfg.make_ebb();
|
||||
let ebb2 = func.dfg.make_ebb();
|
||||
let block0 = func.dfg.make_block();
|
||||
let cond = func.dfg.append_block_param(block0, types::I32);
|
||||
let block1 = func.dfg.make_block();
|
||||
let block2 = func.dfg.make_block();
|
||||
|
||||
let br_ebb0_ebb2;
|
||||
let br_ebb1_ebb1;
|
||||
let jmp_ebb0_ebb1;
|
||||
let jmp_ebb1_ebb2;
|
||||
let br_block0_block2;
|
||||
let br_block1_block1;
|
||||
let jmp_block0_block1;
|
||||
let jmp_block1_block2;
|
||||
|
||||
{
|
||||
let mut cur = FuncCursor::new(&mut func);
|
||||
|
||||
cur.insert_ebb(ebb0);
|
||||
br_ebb0_ebb2 = cur.ins().brnz(cond, ebb2, &[]);
|
||||
jmp_ebb0_ebb1 = cur.ins().jump(ebb1, &[]);
|
||||
cur.insert_block(block0);
|
||||
br_block0_block2 = cur.ins().brnz(cond, block2, &[]);
|
||||
jmp_block0_block1 = cur.ins().jump(block1, &[]);
|
||||
|
||||
cur.insert_ebb(ebb1);
|
||||
br_ebb1_ebb1 = cur.ins().brnz(cond, ebb1, &[]);
|
||||
jmp_ebb1_ebb2 = cur.ins().jump(ebb2, &[]);
|
||||
cur.insert_block(block1);
|
||||
br_block1_block1 = cur.ins().brnz(cond, block1, &[]);
|
||||
jmp_block1_block2 = cur.ins().jump(block2, &[]);
|
||||
|
||||
cur.insert_ebb(ebb2);
|
||||
cur.insert_block(block2);
|
||||
}
|
||||
|
||||
let mut cfg = ControlFlowGraph::with_function(&func);
|
||||
|
||||
{
|
||||
let ebb0_predecessors = cfg.pred_iter(ebb0).collect::<Vec<_>>();
|
||||
let ebb1_predecessors = cfg.pred_iter(ebb1).collect::<Vec<_>>();
|
||||
let ebb2_predecessors = cfg.pred_iter(ebb2).collect::<Vec<_>>();
|
||||
let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>();
|
||||
let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>();
|
||||
let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>();
|
||||
|
||||
let ebb0_successors = cfg.succ_iter(ebb0).collect::<Vec<_>>();
|
||||
let ebb1_successors = cfg.succ_iter(ebb1).collect::<Vec<_>>();
|
||||
let ebb2_successors = cfg.succ_iter(ebb2).collect::<Vec<_>>();
|
||||
let block0_successors = cfg.succ_iter(block0).collect::<Vec<_>>();
|
||||
let block1_successors = cfg.succ_iter(block1).collect::<Vec<_>>();
|
||||
let block2_successors = cfg.succ_iter(block2).collect::<Vec<_>>();
|
||||
|
||||
assert_eq!(ebb0_predecessors.len(), 0);
|
||||
assert_eq!(ebb1_predecessors.len(), 2);
|
||||
assert_eq!(ebb2_predecessors.len(), 2);
|
||||
assert_eq!(block0_predecessors.len(), 0);
|
||||
assert_eq!(block1_predecessors.len(), 2);
|
||||
assert_eq!(block2_predecessors.len(), 2);
|
||||
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb0, jmp_ebb0_ebb1)),
|
||||
block1_predecessors.contains(&BlockPredecessor::new(block0, jmp_block0_block1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
|
||||
block1_predecessors.contains(&BlockPredecessor::new(block1, br_block1_block1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
|
||||
block2_predecessors.contains(&BlockPredecessor::new(block0, br_block0_block2)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
|
||||
block2_predecessors.contains(&BlockPredecessor::new(block1, jmp_block1_block2)),
|
||||
true
|
||||
);
|
||||
|
||||
assert_eq!(ebb0_successors, [ebb1, ebb2]);
|
||||
assert_eq!(ebb1_successors, [ebb1, ebb2]);
|
||||
assert_eq!(ebb2_successors, []);
|
||||
assert_eq!(block0_successors, [block1, block2]);
|
||||
assert_eq!(block1_successors, [block1, block2]);
|
||||
assert_eq!(block2_successors, []);
|
||||
}
|
||||
|
||||
// Change some instructions and recompute ebb0
|
||||
func.dfg.replace(br_ebb0_ebb2).brnz(cond, ebb1, &[]);
|
||||
func.dfg.replace(jmp_ebb0_ebb1).return_(&[]);
|
||||
cfg.recompute_ebb(&mut func, ebb0);
|
||||
let br_ebb0_ebb1 = br_ebb0_ebb2;
|
||||
// Change some instructions and recompute block0
|
||||
func.dfg.replace(br_block0_block2).brnz(cond, block1, &[]);
|
||||
func.dfg.replace(jmp_block0_block1).return_(&[]);
|
||||
cfg.recompute_block(&mut func, block0);
|
||||
let br_block0_block1 = br_block0_block2;
|
||||
|
||||
{
|
||||
let ebb0_predecessors = cfg.pred_iter(ebb0).collect::<Vec<_>>();
|
||||
let ebb1_predecessors = cfg.pred_iter(ebb1).collect::<Vec<_>>();
|
||||
let ebb2_predecessors = cfg.pred_iter(ebb2).collect::<Vec<_>>();
|
||||
let block0_predecessors = cfg.pred_iter(block0).collect::<Vec<_>>();
|
||||
let block1_predecessors = cfg.pred_iter(block1).collect::<Vec<_>>();
|
||||
let block2_predecessors = cfg.pred_iter(block2).collect::<Vec<_>>();
|
||||
|
||||
let ebb0_successors = cfg.succ_iter(ebb0);
|
||||
let ebb1_successors = cfg.succ_iter(ebb1);
|
||||
let ebb2_successors = cfg.succ_iter(ebb2);
|
||||
let block0_successors = cfg.succ_iter(block0);
|
||||
let block1_successors = cfg.succ_iter(block1);
|
||||
let block2_successors = cfg.succ_iter(block2);
|
||||
|
||||
assert_eq!(ebb0_predecessors.len(), 0);
|
||||
assert_eq!(ebb1_predecessors.len(), 2);
|
||||
assert_eq!(ebb2_predecessors.len(), 1);
|
||||
assert_eq!(block0_predecessors.len(), 0);
|
||||
assert_eq!(block1_predecessors.len(), 2);
|
||||
assert_eq!(block2_predecessors.len(), 1);
|
||||
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb1)),
|
||||
block1_predecessors.contains(&BlockPredecessor::new(block0, br_block0_block1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
|
||||
block1_predecessors.contains(&BlockPredecessor::new(block1, br_block1_block1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
|
||||
block2_predecessors.contains(&BlockPredecessor::new(block0, br_block0_block2)),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
|
||||
block2_predecessors.contains(&BlockPredecessor::new(block1, jmp_block1_block2)),
|
||||
true
|
||||
);
|
||||
|
||||
assert_eq!(ebb0_successors.collect::<Vec<_>>(), [ebb1]);
|
||||
assert_eq!(ebb1_successors.collect::<Vec<_>>(), [ebb1, ebb2]);
|
||||
assert_eq!(ebb2_successors.collect::<Vec<_>>(), []);
|
||||
assert_eq!(block0_successors.collect::<Vec<_>>(), [block1]);
|
||||
assert_eq!(block1_successors.collect::<Vec<_>>(), [block1, block2]);
|
||||
assert_eq!(block2_successors.collect::<Vec<_>>(), []);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user