* Verifier now accepts multiple errors (fixes #387).
This commit is contained in:
committed by
Dan Gohman
parent
3f582f7cbd
commit
dbc547091f
@@ -7,7 +7,7 @@ use ir::instructions::BranchInfo;
|
||||
use isa;
|
||||
use packed_option::PackedOption;
|
||||
use timing;
|
||||
use verifier::VerifierResult;
|
||||
use verifier::{VerifierErrors, VerifierStepResult};
|
||||
|
||||
/// Verify that CPU flags are used correctly.
|
||||
///
|
||||
@@ -25,7 +25,8 @@ pub fn verify_flags(
|
||||
func: &ir::Function,
|
||||
cfg: &ControlFlowGraph,
|
||||
isa: Option<&isa::TargetIsa>,
|
||||
) -> VerifierResult<()> {
|
||||
errors: &mut VerifierErrors,
|
||||
) -> VerifierStepResult<()> {
|
||||
let _tt = timing::verify_flags();
|
||||
let mut verifier = FlagsVerifier {
|
||||
func,
|
||||
@@ -33,7 +34,7 @@ pub fn verify_flags(
|
||||
encinfo: isa.map(|isa| isa.encoding_info()),
|
||||
livein: EntityMap::new(),
|
||||
};
|
||||
verifier.check()
|
||||
verifier.check(errors)
|
||||
}
|
||||
|
||||
struct FlagsVerifier<'a> {
|
||||
@@ -46,7 +47,7 @@ struct FlagsVerifier<'a> {
|
||||
}
|
||||
|
||||
impl<'a> FlagsVerifier<'a> {
|
||||
fn check(&mut self) -> VerifierResult<()> {
|
||||
fn check(&mut self, errors: &mut VerifierErrors) -> VerifierStepResult<()> {
|
||||
// List of EBBs that need to be processed. EBBs may be re-added to this list when we detect
|
||||
// that one of their successor blocks needs a live-in flags value.
|
||||
let mut worklist = SparseSet::new();
|
||||
@@ -55,7 +56,7 @@ impl<'a> FlagsVerifier<'a> {
|
||||
}
|
||||
|
||||
while let Some(ebb) = worklist.pop() {
|
||||
if let Some(value) = self.visit_ebb(ebb)? {
|
||||
if let Some(value) = self.visit_ebb(ebb, errors)? {
|
||||
// The EBB has live-in flags. Check if the value changed.
|
||||
match self.livein[ebb].expand() {
|
||||
// Revisit any predecessor blocks the first time we see a live-in for `ebb`.
|
||||
@@ -66,7 +67,13 @@ impl<'a> FlagsVerifier<'a> {
|
||||
}
|
||||
}
|
||||
Some(old) if old != value => {
|
||||
return err!(ebb, "conflicting live-in CPU flags: {} and {}", old, value);
|
||||
return fatal!(
|
||||
errors,
|
||||
ebb,
|
||||
"conflicting live-in CPU flags: {} and {}",
|
||||
old,
|
||||
value
|
||||
);
|
||||
}
|
||||
x => assert_eq!(x, Some(value)),
|
||||
}
|
||||
@@ -80,7 +87,11 @@ impl<'a> FlagsVerifier<'a> {
|
||||
}
|
||||
|
||||
/// Check flags usage in `ebb` and return the live-in flags value, if any.
|
||||
fn visit_ebb(&self, ebb: ir::Ebb) -> VerifierResult<Option<ir::Value>> {
|
||||
fn visit_ebb(
|
||||
&self,
|
||||
ebb: ir::Ebb,
|
||||
errors: &mut VerifierErrors,
|
||||
) -> VerifierStepResult<Option<ir::Value>> {
|
||||
// The single currently live flags value.
|
||||
let mut live_val = None;
|
||||
|
||||
@@ -93,7 +104,7 @@ impl<'a> FlagsVerifier<'a> {
|
||||
// We've reached the def of `live_flags`, so it is no longer live above.
|
||||
live_val = None;
|
||||
} else if self.func.dfg.value_type(res).is_flags() {
|
||||
return err!(inst, "{} clobbers live CPU flags in {}", res, live);
|
||||
return fatal!(errors, inst, "{} clobbers live CPU flags in {}", res, live);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,14 +115,14 @@ impl<'a> FlagsVerifier<'a> {
|
||||
.and_then(|ei| ei.operand_constraints(self.func.encodings[inst]))
|
||||
.map_or(false, |c| c.clobbers_flags) && live_val.is_some()
|
||||
{
|
||||
return err!(inst, "encoding clobbers live CPU flags in {}", live);
|
||||
return fatal!(errors, inst, "encoding clobbers live CPU flags in {}", live);
|
||||
}
|
||||
}
|
||||
|
||||
// Now look for live ranges of CPU flags that end here.
|
||||
for &arg in self.func.dfg.inst_args(inst) {
|
||||
if self.func.dfg.value_type(arg).is_flags() {
|
||||
merge(&mut live_val, arg, inst)?;
|
||||
merge(&mut live_val, arg, inst, errors)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,13 +131,13 @@ impl<'a> FlagsVerifier<'a> {
|
||||
BranchInfo::NotABranch => {}
|
||||
BranchInfo::SingleDest(dest, _) => {
|
||||
if let Some(val) = self.livein[dest].expand() {
|
||||
merge(&mut live_val, val, inst)?;
|
||||
merge(&mut live_val, val, inst, errors)?;
|
||||
}
|
||||
}
|
||||
BranchInfo::Table(jt) => {
|
||||
for (_, dest) in self.func.jump_tables[jt].entries() {
|
||||
if let Some(val) = self.livein[dest].expand() {
|
||||
merge(&mut live_val, val, inst)?;
|
||||
merge(&mut live_val, val, inst, errors)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,10 +150,15 @@ impl<'a> FlagsVerifier<'a> {
|
||||
}
|
||||
|
||||
// Merge live flags values, or return an error on conflicting values.
|
||||
fn merge(a: &mut Option<ir::Value>, b: ir::Value, inst: ir::Inst) -> VerifierResult<()> {
|
||||
fn merge(
|
||||
a: &mut Option<ir::Value>,
|
||||
b: ir::Value,
|
||||
inst: ir::Inst,
|
||||
errors: &mut VerifierErrors,
|
||||
) -> VerifierStepResult<()> {
|
||||
if let Some(va) = *a {
|
||||
if b != va {
|
||||
return err!(inst, "conflicting live CPU flags: {} and {}", va, b);
|
||||
return fatal!(errors, inst, "conflicting live CPU flags: {} and {}", va, b);
|
||||
}
|
||||
} else {
|
||||
*a = Some(b);
|
||||
|
||||
Reference in New Issue
Block a user