Add verification pass to migrate from EBB to BB.
This commit is contained in:
committed by
Nicolas B. Pierron
parent
b35227b417
commit
460fdaa34d
@@ -267,6 +267,8 @@ struct Verifier<'a> {
|
|||||||
expected_cfg: ControlFlowGraph,
|
expected_cfg: ControlFlowGraph,
|
||||||
expected_domtree: DominatorTree,
|
expected_domtree: DominatorTree,
|
||||||
isa: Option<&'a dyn TargetIsa>,
|
isa: Option<&'a dyn TargetIsa>,
|
||||||
|
// To be removed when #796 is completed.
|
||||||
|
verify_encodable_as_bb: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Verifier<'a> {
|
impl<'a> Verifier<'a> {
|
||||||
@@ -278,6 +280,7 @@ impl<'a> Verifier<'a> {
|
|||||||
expected_cfg,
|
expected_cfg,
|
||||||
expected_domtree,
|
expected_domtree,
|
||||||
isa: fisa.isa,
|
isa: fisa.isa,
|
||||||
|
verify_encodable_as_bb: std::env::var("CRANELIFT_BB").is_ok(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,6 +471,53 @@ impl<'a> Verifier<'a> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check that the given EBB can be encoded as a BB, by checking that only
|
||||||
|
/// branching instructions are ending the EBB.
|
||||||
|
fn encodable_as_bb(&self, ebb: Ebb, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
|
||||||
|
// Skip this verification if the environment variable is not set.
|
||||||
|
if !self.verify_encodable_as_bb {
|
||||||
|
return Ok(());
|
||||||
|
};
|
||||||
|
|
||||||
|
let dfg = &self.func.dfg;
|
||||||
|
let inst_iter = self.func.layout.ebb_insts(ebb);
|
||||||
|
// Skip non-branching instructions.
|
||||||
|
let mut inst_iter = inst_iter.skip_while(|&inst| !dfg[inst].opcode().is_branch());
|
||||||
|
|
||||||
|
let branch = match inst_iter.next() {
|
||||||
|
// There is no branch in the current EBB.
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(br) => br,
|
||||||
|
};
|
||||||
|
|
||||||
|
let after_branch = match inst_iter.next() {
|
||||||
|
// The branch is also the terminator.
|
||||||
|
None => return Ok(()),
|
||||||
|
Some(inst) => inst,
|
||||||
|
};
|
||||||
|
|
||||||
|
let after_branch_opcode = dfg[after_branch].opcode();
|
||||||
|
if !after_branch_opcode.is_terminator() {
|
||||||
|
return fatal!(
|
||||||
|
errors,
|
||||||
|
branch,
|
||||||
|
"branch followed by a non-terminator instruction."
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Allow only one conditional branch and a fallthrough implemented with
|
||||||
|
// a jump or fallthrough instruction. Any other, which returns or check
|
||||||
|
// a different condition would have to be moved to a different EBB.
|
||||||
|
match after_branch_opcode {
|
||||||
|
Opcode::Fallthrough | Opcode::Jump => Ok(()),
|
||||||
|
_ => fatal!(
|
||||||
|
errors,
|
||||||
|
after_branch,
|
||||||
|
"terminator instruction not fallthrough or jump"
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn ebb_integrity(
|
fn ebb_integrity(
|
||||||
&self,
|
&self,
|
||||||
ebb: Ebb,
|
ebb: Ebb,
|
||||||
@@ -1744,6 +1794,7 @@ impl<'a> Verifier<'a> {
|
|||||||
self.verify_encoding(inst, errors)?;
|
self.verify_encoding(inst, errors)?;
|
||||||
self.immediate_constraints(inst, errors)?;
|
self.immediate_constraints(inst, errors)?;
|
||||||
}
|
}
|
||||||
|
self.encodable_as_bb(ebb, errors)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
verify_flags(self.func, &self.expected_cfg, self.isa, errors)?;
|
verify_flags(self.func, &self.expected_cfg, self.isa, errors)?;
|
||||||
|
|||||||
Reference in New Issue
Block a user