Verify that all predecessors to an EBB are valid branches, and have the EBB recorded as a successor.

This commit is contained in:
Angus Holder
2017-03-20 11:07:50 +00:00
committed by Jakob Stoklund Olesen
parent 8b300a9efb
commit d383a41851
2 changed files with 43 additions and 2 deletions

View File

@@ -72,6 +72,11 @@ impl JumpTableData {
.enumerate())
}
/// Checks if any of the entries branch to `ebb`.
pub fn branches_to(&self, ebb: Ebb) -> bool {
self.table.iter().any(|target_ebb| target_ebb.expand() == Some(ebb))
}
/// Access the whole table as a mutable slice.
pub fn as_mut_slice(&mut self) -> &mut [PackedOption<Ebb>] {
self.table.as_mut_slice()

View File

@@ -24,9 +24,9 @@
//!
//! Control flow graph and dominator tree integrity:
//!
//! TODO:
//! - All predecessors in the CFG must be branches to the EBB.
//! - All branches to an EBB must be present in the CFG.
//! TODO:
//! - A recomputed dominator tree is identical to the existing one.
//!
//! Type checking
@@ -54,7 +54,7 @@
//! of arguments must match the destination type, and the lane indexes must be in range.
use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, Value};
use ir::instructions::InstructionFormat;
use ir::instructions::{InstructionFormat, BranchInfo};
use ir::entities::AnyEntity;
use cfg::ControlFlowGraph;
use dominator_tree::DominatorTree;
@@ -342,12 +342,48 @@ impl<'a> Verifier<'a> {
Ok(())
}
fn cfg_integrity(&self, ebb: Ebb) -> Result<()> {
for &(pred_ebb, pred_inst) in self.cfg.get_predecessors(ebb) {
// All predecessors in the CFG must be branches to the EBB
match self.func.dfg[pred_inst].analyze_branch(&self.func.dfg.value_lists) {
BranchInfo::SingleDest(target_ebb, _) => {
if target_ebb != ebb {
return err!(ebb,
"has predecessor {} in {} which does not branch here",
pred_inst,
pred_ebb);
}
}
BranchInfo::Table(jt) => {
if !self.func.jump_tables[jt].branches_to(ebb) {
return err!(ebb,
"has predecessor {} using {} in {} which never branches here",
pred_inst,
jt,
pred_ebb);
}
}
BranchInfo::NotABranch => {
return err!(ebb, "has predecessor {} which is not a branch", pred_inst);
}
}
// All EBBs branching to `ebb` have it recorded as a successor in the CFG.
if !self.cfg.get_successors(pred_ebb).contains(&ebb) {
return err!(ebb,
"predecessor {} does not have this EBB recorded as a successor",
pred_ebb);
}
}
Ok(())
}
pub fn run(&self) -> Result<()> {
for ebb in self.func.layout.ebbs() {
for inst in self.func.layout.ebb_insts(ebb) {
self.ebb_integrity(ebb, inst)?;
self.instruction_integrity(inst)?;
}
self.cfg_integrity(ebb)?;
}
Ok(())
}