Verify that values are defined by an EBB/instruction that dominates the instruction that uses them.
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
298cf2ed21
commit
c596ea1ac1
@@ -68,8 +68,20 @@ impl DominatorTree {
|
||||
/// is unreachable.
|
||||
///
|
||||
/// An instruction is considered to dominate itself.
|
||||
pub fn dominates(&self, a: Inst, mut b: Inst, layout: &Layout) -> bool {
|
||||
pub fn dominates(&self, a: Inst, b: Inst, layout: &Layout) -> bool {
|
||||
let ebb_a = layout.inst_ebb(a).expect("Instruction not in layout.");
|
||||
self.ebb_dominates(ebb_a, b, layout) && layout.cmp(a, b) != Ordering::Greater
|
||||
}
|
||||
|
||||
/// Returns `true` if `ebb_a` dominates `b`.
|
||||
///
|
||||
/// This means that every control-flow path from the function entry to `b` must go through
|
||||
/// `ebb_a`.
|
||||
///
|
||||
/// Dominance is ill defined for unreachable blocks. This function can always determine
|
||||
/// dominance for instructions in the same EBB, but otherwise returns `false` if either block
|
||||
/// is unreachable.
|
||||
pub fn ebb_dominates(&self, ebb_a: Ebb, mut b: Inst, layout: &Layout) -> bool {
|
||||
let mut ebb_b = layout.inst_ebb(b).expect("Instruction not in layout.");
|
||||
let rpo_a = self.nodes[ebb_a].rpo_number;
|
||||
|
||||
@@ -80,7 +92,7 @@ impl DominatorTree {
|
||||
ebb_b = layout.inst_ebb(b).expect("Dominator got removed.");
|
||||
}
|
||||
|
||||
ebb_a == ebb_b && layout.cmp(a, b) != Ordering::Greater
|
||||
ebb_a == ebb_b
|
||||
}
|
||||
|
||||
/// Compute the common dominator of two basic blocks.
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
//!
|
||||
//! - Values must be defined by an instruction that exists and that is inserted in
|
||||
//! an EBB, or be an argument of an existing EBB.
|
||||
//! TODO:
|
||||
//! - Values used by an instruction must dominate the instruction.
|
||||
//!
|
||||
//! 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.
|
||||
//! - A recomputed dominator tree is identical to the existing one.
|
||||
@@ -56,6 +56,8 @@
|
||||
use ir::{types, Function, ValueDef, Ebb, Inst, SigRef, FuncRef, ValueList, JumpTable, Value};
|
||||
use ir::instructions::InstructionFormat;
|
||||
use ir::entities::AnyEntity;
|
||||
use cfg::ControlFlowGraph;
|
||||
use dominator_tree::DominatorTree;
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::result;
|
||||
|
||||
@@ -101,11 +103,19 @@ pub fn verify_function(func: &Function) -> Result<()> {
|
||||
|
||||
struct Verifier<'a> {
|
||||
func: &'a Function,
|
||||
cfg: ControlFlowGraph,
|
||||
domtree: DominatorTree,
|
||||
}
|
||||
|
||||
impl<'a> Verifier<'a> {
|
||||
pub fn new(func: &'a Function) -> Verifier {
|
||||
Verifier { func: func }
|
||||
let cfg = ControlFlowGraph::with_function(func);
|
||||
let domtree = DominatorTree::with_function(func, &cfg);
|
||||
Verifier {
|
||||
func: func,
|
||||
cfg: cfg,
|
||||
domtree: domtree,
|
||||
}
|
||||
}
|
||||
|
||||
fn ebb_integrity(&self, ebb: Ebb, inst: Inst) -> Result<()> {
|
||||
@@ -291,32 +301,42 @@ impl<'a> Verifier<'a> {
|
||||
|
||||
// SSA form
|
||||
match dfg.value_def(v) {
|
||||
// Value is defined by an instruction that exists and is inserted in an EBB.
|
||||
ValueDef::Res(def_inst, _) => {
|
||||
// Value is defined by an instruction that exists.
|
||||
if !dfg.insts.is_valid(def_inst) {
|
||||
return err!(loc_inst,
|
||||
"{} is defined by invalid instruction {}",
|
||||
v,
|
||||
def_inst);
|
||||
}
|
||||
// Defining instruction is inserted in an EBB.
|
||||
if self.func.layout.inst_ebb(def_inst) == None {
|
||||
return err!(loc_inst,
|
||||
"{} is defined by {} which has no EBB",
|
||||
v,
|
||||
def_inst);
|
||||
}
|
||||
// Defining instruction dominates the instruction that uses the value.
|
||||
if !self.domtree.dominates(def_inst, loc_inst, &self.func.layout) {
|
||||
return err!(loc_inst, "uses value from non-dominating {}", def_inst);
|
||||
}
|
||||
}
|
||||
// Value is defined by an existing EBB which is inserted in the layout.
|
||||
ValueDef::Arg(ebb, _) => {
|
||||
// Value is defined by an existing EBB.
|
||||
if !dfg.ebb_is_valid(ebb) {
|
||||
return err!(loc_inst, "{} is defined by invalid EBB {}", v, ebb);
|
||||
}
|
||||
// Defining EBB is inserted in the layout
|
||||
if !self.func.layout.is_ebb_inserted(ebb) {
|
||||
return err!(loc_inst,
|
||||
"{} is defined by {} which is not in the layout",
|
||||
v,
|
||||
ebb);
|
||||
}
|
||||
// The defining EBB dominates the instruction using this value.
|
||||
if !self.domtree.ebb_dominates(ebb, loc_inst, &self.func.layout) {
|
||||
return err!(loc_inst, "uses value arg from non-dominating {}", ebb);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
Reference in New Issue
Block a user