Promote the BasicBlock tuple to a real struct;

It makes reading code that uses it easier to understand.
This commit is contained in:
Benjamin Bouvier
2018-07-19 15:29:29 +02:00
committed by Dan Gohman
parent ce177d643e
commit f72ff791b4
12 changed files with 127 additions and 50 deletions

View File

@@ -2,7 +2,7 @@
use std::fmt::{Display, Formatter, Result, Write}; use std::fmt::{Display, Formatter, Result, Write};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::instructions::BranchInfo; use ir::instructions::BranchInfo;
use ir::Function; use ir::Function;
@@ -61,7 +61,7 @@ impl<'a> CFGPrinter<'a> {
fn cfg_connections(&self, w: &mut Write) -> Result { fn cfg_connections(&self, w: &mut Write) -> Result {
for ebb in &self.func.layout { for ebb in &self.func.layout {
for (parent, inst) in self.cfg.pred_iter(ebb) { for BasicBlock { ebb: parent, inst } in self.cfg.pred_iter(ebb) {
writeln!(w, " {}:{} -> {}", parent, inst, ebb)?; writeln!(w, " {}:{} -> {}", parent, inst, ebb)?;
} }
} }

View File

@@ -177,19 +177,19 @@ impl DominatorTree {
layout: &Layout, layout: &Layout,
) -> BasicBlock { ) -> BasicBlock {
loop { loop {
match self.rpo_cmp_ebb(a.0, b.0) { match self.rpo_cmp_ebb(a.ebb, b.ebb) {
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.ebb].idom.expect("Unreachable basic block?");
b = ( b = BasicBlock::new(
layout.inst_ebb(idom).expect("Dangling idom instruction"), layout.inst_ebb(idom).expect("Dangling idom instruction"),
idom, idom,
); );
} }
Ordering::Greater => { Ordering::Greater => {
// `b` comes before `a` in the RPO. Move `a` up. // `b` comes before `a` in the RPO. Move `a` up.
let idom = self.nodes[a.0].idom.expect("Unreachable basic block?"); let idom = self.nodes[a.ebb].idom.expect("Unreachable basic block?");
a = ( a = BasicBlock::new(
layout.inst_ebb(idom).expect("Dangling idom instruction"), layout.inst_ebb(idom).expect("Dangling idom instruction"),
idom, idom,
); );
@@ -198,10 +198,13 @@ impl DominatorTree {
} }
} }
debug_assert_eq!(a.0, b.0, "Unreachable block passed to common_dominator?"); debug_assert_eq!(
a.ebb, b.ebb,
"Unreachable block passed to common_dominator?"
);
// We're in the same EBB. The common dominator is the earlier instruction. // We're in the same EBB. The common dominator is the earlier instruction.
if layout.cmp(a.1, b.1) == Ordering::Less { if layout.cmp(a.inst, b.inst) == Ordering::Less {
a a
} else { } else {
b b
@@ -420,7 +423,7 @@ impl DominatorTree {
// Note that during the first pass, `rpo_number` is 1 for reachable blocks that haven't // Note that during the first pass, `rpo_number` is 1 for reachable blocks that haven't
// been visited yet, 0 for unreachable blocks. // been visited yet, 0 for unreachable blocks.
let mut reachable_preds = cfg.pred_iter(ebb) let mut reachable_preds = cfg.pred_iter(ebb)
.filter(|&(pred, _)| self.nodes[pred].rpo_number > 1); .filter(|&BasicBlock { ebb: pred, .. }| self.nodes[pred].rpo_number > 1);
// The RPO must visit at least one predecessor before this node. // The RPO must visit at least one predecessor before this node.
let mut idom = reachable_preds let mut idom = reachable_preds
@@ -431,7 +434,7 @@ impl DominatorTree {
idom = self.common_dominator(idom, pred, layout); idom = self.common_dominator(idom, pred, layout);
} }
idom.1 idom.inst
} }
} }

View File

@@ -31,7 +31,20 @@ use std::mem;
use timing; use timing;
/// 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); #[derive(PartialEq, Eq)]
pub struct BasicBlock {
/// Enclosing Ebb key.
pub ebb: Ebb,
/// 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 }
}
}
/// 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)]
@@ -110,11 +123,11 @@ impl ControlFlowGraph {
for inst in func.layout.ebb_insts(ebb) { for inst in func.layout.ebb_insts(ebb) {
match func.dfg.analyze_branch(inst) { match func.dfg.analyze_branch(inst) {
BranchInfo::SingleDest(dest, _) => { BranchInfo::SingleDest(dest, _) => {
self.add_edge((ebb, inst), dest); self.add_edge(BasicBlock::new(ebb, inst), dest);
} }
BranchInfo::Table(jt) => { BranchInfo::Table(jt) => {
for (_, dest) in func.jump_tables[jt].entries() { for (_, dest) in func.jump_tables[jt].entries() {
self.add_edge((ebb, inst), dest); self.add_edge(BasicBlock::new(ebb, inst), dest);
} }
} }
BranchInfo::NotABranch => {} BranchInfo::NotABranch => {}
@@ -148,12 +161,12 @@ impl ControlFlowGraph {
} }
fn add_edge(&mut self, from: BasicBlock, to: Ebb) { fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
self.data[from.0] self.data[from.ebb]
.successors .successors
.insert(to, &mut self.succ_forest, &()); .insert(to, &mut self.succ_forest, &());
self.data[to] self.data[to]
.predecessors .predecessors
.insert(from.1, from.0, &mut self.pred_forest, &()); .insert(from.inst, from.ebb, &mut self.pred_forest, &());
} }
/// Get an iterator over the CFG predecessors to `ebb`. /// Get an iterator over the CFG predecessors to `ebb`.
@@ -186,7 +199,7 @@ 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().map(|(i, e)| (e, i)) self.0.next().map(|(i, e)| BasicBlock::new(e, i))
} }
} }
@@ -268,10 +281,22 @@ mod tests {
assert_eq!(ebb1_predecessors.len(), 2); assert_eq!(ebb1_predecessors.len(), 2);
assert_eq!(ebb2_predecessors.len(), 2); assert_eq!(ebb2_predecessors.len(), 2);
assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true); assert_eq!(
assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true); ebb1_predecessors.contains(&BasicBlock::new(ebb0, jmp_ebb0_ebb1)),
assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true); true
assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true); );
assert_eq!(
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
true
);
assert_eq!(
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
true
);
assert_eq!(
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
true
);
assert_eq!(ebb0_successors, [ebb1, ebb2]); assert_eq!(ebb0_successors, [ebb1, ebb2]);
assert_eq!(ebb1_successors, [ebb1, ebb2]); assert_eq!(ebb1_successors, [ebb1, ebb2]);
@@ -297,10 +322,22 @@ mod tests {
assert_eq!(ebb1_predecessors.len(), 2); assert_eq!(ebb1_predecessors.len(), 2);
assert_eq!(ebb2_predecessors.len(), 1); assert_eq!(ebb2_predecessors.len(), 1);
assert_eq!(ebb1_predecessors.contains(&(ebb0, br_ebb0_ebb1)), true); assert_eq!(
assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true); ebb1_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb1)),
assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), false); true
assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true); );
assert_eq!(
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
true
);
assert_eq!(
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
false
);
assert_eq!(
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
true
);
assert_eq!(ebb0_successors.collect::<Vec<_>>(), [ebb1]); assert_eq!(ebb0_successors.collect::<Vec<_>>(), [ebb1]);
assert_eq!(ebb1_successors.collect::<Vec<_>>(), [ebb1, ebb2]); assert_eq!(ebb1_successors.collect::<Vec<_>>(), [ebb1, ebb2]);

View File

@@ -65,7 +65,7 @@
//! instructions. These loops will remain in the program. //! instructions. These loops will remain in the program.
use cursor::{Cursor, CursorPosition, FuncCursor}; use cursor::{Cursor, CursorPosition, FuncCursor};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::{self, Ebb, Inst, InstBuilder, InstructionData, Opcode, Type, Value, ValueDef}; use ir::{self, Ebb, Inst, InstBuilder, InstructionData, Opcode, Type, Value, ValueDef};
use std::iter; use std::iter;
use std::vec::Vec; use std::vec::Vec;
@@ -126,7 +126,7 @@ fn split_any(
// We have split the value requested, and now we may need to fix some EBB predecessors. // We have split the value requested, and now we may need to fix some EBB predecessors.
while let Some(repair) = repairs.pop() { while let Some(repair) = repairs.pop() {
for (_, inst) in cfg.pred_iter(repair.ebb) { for BasicBlock { inst, .. } in cfg.pred_iter(repair.ebb) {
let branch_opc = pos.func.dfg[inst].opcode(); let branch_opc = pos.func.dfg[inst].opcode();
debug_assert!( debug_assert!(
branch_opc.is_branch(), branch_opc.is_branch(),

View File

@@ -3,7 +3,7 @@
use cursor::{Cursor, FuncCursor}; use cursor::{Cursor, FuncCursor};
use dominator_tree::DominatorTree; use dominator_tree::DominatorTree;
use entity::{EntityList, ListPool}; use entity::{EntityList, ListPool};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use fx::FxHashSet; use fx::FxHashSet;
use ir::{DataFlowGraph, Ebb, Function, Inst, InstBuilder, Layout, Opcode, Type, Value}; use ir::{DataFlowGraph, Ebb, Function, Inst, InstBuilder, Layout, Opcode, Type, Value};
use loop_analysis::{Loop, LoopAnalysis}; use loop_analysis::{Loop, LoopAnalysis};
@@ -77,7 +77,10 @@ fn create_pre_header(
for typ in header_args_types { for typ in header_args_types {
pre_header_args_value.push(func.dfg.append_ebb_param(pre_header, typ), pool); pre_header_args_value.push(func.dfg.append_ebb_param(pre_header, typ), pool);
} }
for (_, last_inst) in cfg.pred_iter(header) { for BasicBlock {
inst: last_inst, ..
} in cfg.pred_iter(header)
{
// We only follow normal edges (not the back edges) // We only follow normal edges (not the back edges)
if !domtree.dominates(header, last_inst, &func.layout) { if !domtree.dominates(header, last_inst, &func.layout) {
change_branch_jump_destination(last_inst, pre_header, func); change_branch_jump_destination(last_inst, pre_header, func);
@@ -106,7 +109,11 @@ fn has_pre_header(
) -> Option<(Ebb, Inst)> { ) -> Option<(Ebb, Inst)> {
let mut result = None; let mut result = None;
let mut found = false; let mut found = false;
for (pred_ebb, last_inst) in cfg.pred_iter(header) { for BasicBlock {
ebb: pred_ebb,
inst: last_inst,
} in cfg.pred_iter(header)
{
// We only count normal edges (not the back edges) // We only count normal edges (not the back edges)
if !domtree.dominates(header, last_inst, layout) { if !domtree.dominates(header, last_inst, layout) {
if found { if found {

View File

@@ -4,7 +4,7 @@
use dominator_tree::DominatorTree; use dominator_tree::DominatorTree;
use entity::EntityMap; use entity::EntityMap;
use entity::{Keys, PrimaryMap}; use entity::{Keys, PrimaryMap};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::{Ebb, Function, Layout}; use ir::{Ebb, Function, Layout};
use packed_option::PackedOption; use packed_option::PackedOption;
use std::vec::Vec; use std::vec::Vec;
@@ -137,7 +137,10 @@ impl LoopAnalysis {
) { ) {
// We traverse the CFG in reverse postorder // We traverse the CFG in reverse postorder
for &ebb in domtree.cfg_postorder().iter().rev() { for &ebb in domtree.cfg_postorder().iter().rev() {
for (_, pred_inst) in cfg.pred_iter(ebb) { for BasicBlock {
inst: pred_inst, ..
} in cfg.pred_iter(ebb)
{
// If the ebb dominates one of its predecessors it is a back edge // If the ebb dominates one of its predecessors it is a back edge
if domtree.dominates(ebb, pred_inst, layout) { if domtree.dominates(ebb, pred_inst, layout) {
// This ebb is a loop header, so we create its associated loop // This ebb is a loop header, so we create its associated loop
@@ -163,7 +166,11 @@ impl LoopAnalysis {
// We handle each loop header in reverse order, corresponding to a pseudo postorder // We handle each loop header in reverse order, corresponding to a pseudo postorder
// traversal of the graph. // traversal of the graph.
for lp in self.loops().rev() { for lp in self.loops().rev() {
for (pred, pred_inst) in cfg.pred_iter(self.loops[lp].header) { for BasicBlock {
ebb: pred,
inst: pred_inst,
} in cfg.pred_iter(self.loops[lp].header)
{
// We follow the back edges // We follow the back edges
if domtree.dominates(self.loops[lp].header, pred_inst, layout) { if domtree.dominates(self.loops[lp].header, pred_inst, layout) {
stack.push(pred); stack.push(pred);
@@ -213,7 +220,7 @@ impl LoopAnalysis {
// Now we have handled the popped node and need to continue the DFS by adding the // Now we have handled the popped node and need to continue the DFS by adding the
// predecessors of that node // predecessors of that node
if let Some(continue_dfs) = continue_dfs { if let Some(continue_dfs) = continue_dfs {
for (pred, _) in cfg.pred_iter(continue_dfs) { for BasicBlock { ebb: pred, .. } in cfg.pred_iter(continue_dfs) {
stack.push(pred) stack.push(pred)
} }
} }

View File

@@ -9,7 +9,7 @@ use cursor::{Cursor, EncCursor};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use dbg::DisplayList; use dbg::DisplayList;
use dominator_tree::{DominatorTree, DominatorTreePreorder}; use dominator_tree::{DominatorTree, DominatorTreePreorder};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use fx::FxHashMap; use fx::FxHashMap;
use ir::{self, InstBuilder, ProgramOrder}; use ir::{self, InstBuilder, ProgramOrder};
use ir::{Ebb, ExpandedProgramPoint, Function, Inst, Value}; use ir::{Ebb, ExpandedProgramPoint, Function, Inst, Value};
@@ -174,7 +174,11 @@ impl<'a> Context<'a> {
debug_assert_eq!(num_params, self.func.dfg.num_ebb_params(ebb)); debug_assert_eq!(num_params, self.func.dfg.num_ebb_params(ebb));
// The only way a parameter value can interfere with a predecessor branch is if the EBB is // The only way a parameter value can interfere with a predecessor branch is if the EBB is
// dominating the predecessor branch. That is, we are looking for loop back-edges. // dominating the predecessor branch. That is, we are looking for loop back-edges.
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) { for BasicBlock {
ebb: pred_ebb,
inst: pred_inst,
} in self.cfg.pred_iter(ebb)
{
// The quick pre-order dominance check is accurate because the EBB parameter is defined // The quick pre-order dominance check is accurate because the EBB parameter is defined
// at the top of the EBB before any branches. // at the top of the EBB before any branches.
if !self.preorder.dominates(ebb, pred_ebb) { if !self.preorder.dominates(ebb, pred_ebb) {
@@ -211,7 +215,11 @@ impl<'a> Context<'a> {
fn union_pred_args(&mut self, ebb: Ebb, argnum: usize) { fn union_pred_args(&mut self, ebb: Ebb, argnum: usize) {
let param = self.func.dfg.ebb_params(ebb)[argnum]; let param = self.func.dfg.ebb_params(ebb)[argnum];
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) { for BasicBlock {
ebb: pred_ebb,
inst: pred_inst,
} in self.cfg.pred_iter(ebb)
{
let arg = self.func.dfg.inst_variable_args(pred_inst)[argnum]; let arg = self.func.dfg.inst_variable_args(pred_inst)[argnum];
// Never coalesce incoming function parameters on the stack. These parameters are // Never coalesce incoming function parameters on the stack. These parameters are
@@ -484,7 +492,11 @@ impl<'a> Context<'a> {
// not loop backedges. // not loop backedges.
debug_assert!(self.predecessors.is_empty()); debug_assert!(self.predecessors.is_empty());
debug_assert!(self.backedges.is_empty()); debug_assert!(self.backedges.is_empty());
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) { for BasicBlock {
ebb: pred_ebb,
inst: pred_inst,
} in self.cfg.pred_iter(ebb)
{
if self.preorder.dominates(ebb, pred_ebb) { if self.preorder.dominates(ebb, pred_ebb) {
self.backedges.push(pred_inst); self.backedges.push(pred_inst);
} else { } else {
@@ -915,7 +927,10 @@ impl VirtualCopies {
} }
// This EBB hasn't been seen before. // This EBB hasn't been seen before.
for (_, pred_inst) in cfg.pred_iter(ebb) { for BasicBlock {
inst: pred_inst, ..
} in cfg.pred_iter(ebb)
{
self.branches.push((pred_inst, ebb)); self.branches.push((pred_inst, ebb));
} }
last_ebb = Some(ebb); last_ebb = Some(ebb);

View File

@@ -176,7 +176,7 @@
//! There is some room for improvement. //! There is some room for improvement.
use entity::SparseMap; use entity::SparseMap;
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::dfg::ValueDef; use ir::dfg::ValueDef;
use ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value}; use ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value};
use isa::{EncInfo, OperandConstraint, TargetIsa}; use isa::{EncInfo, OperandConstraint, TargetIsa};
@@ -272,7 +272,11 @@ fn extend_to_use(
while let Some(livein) = worklist.pop() { while let Some(livein) = worklist.pop() {
// We've learned that the value needs to be live-in to the `livein` EBB. // We've learned that the value needs to be live-in to the `livein` EBB.
// Make sure it is also live at all predecessor branches to `livein`. // Make sure it is also live at all predecessor branches to `livein`.
for (pred, branch) in cfg.pred_iter(livein) { for BasicBlock {
ebb: pred,
inst: branch,
} in cfg.pred_iter(livein)
{
if lr.extend_in_ebb(pred, branch, &func.layout, forest) { if lr.extend_in_ebb(pred, branch, &func.layout, forest) {
// This predecessor EBB also became live-in. We need to process it later. // This predecessor EBB also became live-in. We need to process it later.
worklist.push(pred); worklist.push(pred);

View File

@@ -2,7 +2,7 @@
use dbg::DisplayList; use dbg::DisplayList;
use dominator_tree::{DominatorTree, DominatorTreePreorder}; use dominator_tree::{DominatorTree, DominatorTreePreorder};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::{ExpandedProgramPoint, Function}; use ir::{ExpandedProgramPoint, Function};
use regalloc::liveness::Liveness; use regalloc::liveness::Liveness;
use regalloc::virtregs::VirtRegs; use regalloc::virtregs::VirtRegs;
@@ -138,7 +138,7 @@ impl<'a> CssaVerifier<'a> {
fn check_cssa(&self) -> VerifierResult<()> { fn check_cssa(&self) -> VerifierResult<()> {
for ebb in self.func.layout.ebbs() { for ebb in self.func.layout.ebbs() {
let ebb_params = self.func.dfg.ebb_params(ebb); let ebb_params = self.func.dfg.ebb_params(ebb);
for (_, pred) in self.cfg.pred_iter(ebb) { for BasicBlock { inst: pred, .. } in self.cfg.pred_iter(ebb) {
let pred_args = self.func.dfg.inst_variable_args(pred); let pred_args = self.func.dfg.inst_variable_args(pred);
// This should have been caught by an earlier verifier pass. // This should have been caught by an earlier verifier pass.
assert_eq!( assert_eq!(

View File

@@ -1,7 +1,7 @@
//! Verify CPU flags values. //! Verify CPU flags values.
use entity::{EntityMap, SparseSet}; use entity::{EntityMap, SparseSet};
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir; use ir;
use ir::instructions::BranchInfo; use ir::instructions::BranchInfo;
use isa; use isa;
@@ -61,7 +61,7 @@ impl<'a> FlagsVerifier<'a> {
// Revisit any predecessor blocks the first time we see a live-in for `ebb`. // Revisit any predecessor blocks the first time we see a live-in for `ebb`.
None => { None => {
self.livein[ebb] = value.into(); self.livein[ebb] = value.into();
for (pred, _) in self.cfg.pred_iter(ebb) { for BasicBlock { ebb: pred, .. } in self.cfg.pred_iter(ebb) {
worklist.insert(pred); worklist.insert(pred);
} }
} }

View File

@@ -1,6 +1,6 @@
//! Liveness verifier. //! Liveness verifier.
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir::entities::AnyEntity; use ir::entities::AnyEntity;
use ir::{ExpandedProgramPoint, Function, Inst, ProgramOrder, ProgramPoint, Value}; use ir::{ExpandedProgramPoint, Function, Inst, ProgramOrder, ProgramPoint, Value};
use isa::TargetIsa; use isa::TargetIsa;
@@ -194,7 +194,7 @@ impl<'a> LivenessVerifier<'a> {
// Check all the EBBs in the interval independently. // Check all the EBBs in the interval independently.
loop { loop {
// If `val` is live-in at `ebb`, it must be live at all the predecessors. // If `val` is live-in at `ebb`, it must be live at all the predecessors.
for (_, pred) in self.cfg.pred_iter(ebb) { for BasicBlock { inst: pred, .. } in self.cfg.pred_iter(ebb) {
if !self.live_at_use(lr, pred) { if !self.live_at_use(lr, pred) {
return err!( return err!(
pred, pred,

View File

@@ -60,7 +60,7 @@ use self::flags::verify_flags;
use dbg::DisplayList; use dbg::DisplayList;
use dominator_tree::DominatorTree; use dominator_tree::DominatorTree;
use entity::SparseSet; use entity::SparseSet;
use flowgraph::ControlFlowGraph; use flowgraph::{BasicBlock, ControlFlowGraph};
use ir; use ir;
use ir::entities::AnyEntity; use ir::entities::AnyEntity;
use ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint}; use ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
@@ -990,8 +990,12 @@ impl<'a> Verifier<'a> {
return err!(ebb, "cfg had unexpected successor(s) {:?}", excess_succs); return err!(ebb, "cfg had unexpected successor(s) {:?}", excess_succs);
} }
expected_preds.extend(self.expected_cfg.pred_iter(ebb).map(|(_, inst)| inst)); expected_preds.extend(
got_preds.extend(cfg.pred_iter(ebb).map(|(_, inst)| inst)); self.expected_cfg
.pred_iter(ebb)
.map(|BasicBlock { inst, .. }| inst),
);
got_preds.extend(cfg.pred_iter(ebb).map(|BasicBlock { inst, .. }| inst));
let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect(); let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
if !missing_preds.is_empty() { if !missing_preds.is_empty() {