Remove macros from verifier; fixes #1248
This removes `report!`, `fatal!`, and `nonfatal!` from the verifier code and replaces them with methods on `VerifierErrors`. In order to maintain similar ease-of-use, `VerifierError` is expanded with several `From` implementations that convert a tuple to a verifier error.
This commit is contained in:
@@ -65,13 +65,13 @@ impl<'a> CssaVerifier<'a> {
|
|||||||
|
|
||||||
for (idx, &val) in values.iter().enumerate() {
|
for (idx, &val) in values.iter().enumerate() {
|
||||||
if !self.func.dfg.value_is_valid(val) {
|
if !self.func.dfg.value_is_valid(val) {
|
||||||
return fatal!(errors, val, "Invalid value in {}", vreg);
|
return errors.fatal((val, format!("Invalid value in {}", vreg)));
|
||||||
}
|
}
|
||||||
if !self.func.dfg.value_is_attached(val) {
|
if !self.func.dfg.value_is_attached(val) {
|
||||||
return fatal!(errors, val, "Detached value in {}", vreg);
|
return errors.fatal((val, format!("Detached value in {}", vreg)));
|
||||||
}
|
}
|
||||||
if self.liveness.get(val).is_none() {
|
if self.liveness.get(val).is_none() {
|
||||||
return fatal!(errors, val, "Value in {} has no live range", vreg);
|
return errors.fatal((val, format!("Value in {} has no live range", vreg)));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check topological ordering with the previous values in the virtual register.
|
// Check topological ordering with the previous values in the virtual register.
|
||||||
@@ -82,29 +82,31 @@ impl<'a> CssaVerifier<'a> {
|
|||||||
let prev_ebb = self.func.layout.pp_ebb(prev_def);
|
let prev_ebb = self.func.layout.pp_ebb(prev_def);
|
||||||
|
|
||||||
if prev_def == def {
|
if prev_def == def {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
val,
|
val,
|
||||||
"Values {} and {} in {} = {} defined at the same program point",
|
format!(
|
||||||
prev_val,
|
"Values {} and {} in {} = {} defined at the same program point",
|
||||||
val,
|
prev_val,
|
||||||
vreg,
|
val,
|
||||||
DisplayList(values)
|
vreg,
|
||||||
);
|
DisplayList(values)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enforce topological ordering of defs in the virtual register.
|
// Enforce topological ordering of defs in the virtual register.
|
||||||
if self.preorder.dominates(def_ebb, prev_ebb)
|
if self.preorder.dominates(def_ebb, prev_ebb)
|
||||||
&& self.domtree.dominates(def, prev_def, &self.func.layout)
|
&& self.domtree.dominates(def, prev_def, &self.func.layout)
|
||||||
{
|
{
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
val,
|
val,
|
||||||
"Value in {} = {} def dominates previous {}",
|
format!(
|
||||||
vreg,
|
"Value in {} = {} def dominates previous {}",
|
||||||
DisplayList(values),
|
vreg,
|
||||||
prev_val
|
DisplayList(values),
|
||||||
);
|
prev_val
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,14 +121,15 @@ impl<'a> CssaVerifier<'a> {
|
|||||||
&& self.domtree.dominates(prev_def, def, &self.func.layout)
|
&& self.domtree.dominates(prev_def, def, &self.func.layout)
|
||||||
{
|
{
|
||||||
if self.liveness[prev_val].overlaps_def(def, def_ebb, &self.func.layout) {
|
if self.liveness[prev_val].overlaps_def(def, def_ebb, &self.func.layout) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
val,
|
val,
|
||||||
"Value def in {} = {} interferes with {}",
|
format!(
|
||||||
vreg,
|
"Value def in {} = {} interferes with {}",
|
||||||
DisplayList(values),
|
vreg,
|
||||||
prev_val
|
DisplayList(values),
|
||||||
);
|
prev_val
|
||||||
|
),
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -152,13 +155,13 @@ impl<'a> CssaVerifier<'a> {
|
|||||||
|
|
||||||
for (&ebb_param, &pred_arg) in ebb_params.iter().zip(pred_args) {
|
for (&ebb_param, &pred_arg) in ebb_params.iter().zip(pred_args) {
|
||||||
if !self.virtregs.same_class(ebb_param, pred_arg) {
|
if !self.virtregs.same_class(ebb_param, pred_arg) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
pred,
|
pred,
|
||||||
"{} and {} must be in the same virtual register",
|
format!(
|
||||||
ebb_param,
|
"{} and {} must be in the same virtual register",
|
||||||
pred_arg
|
ebb_param, pred_arg
|
||||||
);
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,13 +67,10 @@ impl<'a> FlagsVerifier<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(old) if old != value => {
|
Some(old) if old != value => {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
ebb,
|
ebb,
|
||||||
"conflicting live-in CPU flags: {} and {}",
|
format!("conflicting live-in CPU flags: {} and {}", old, value),
|
||||||
old,
|
));
|
||||||
value
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
x => assert_eq!(x, Some(value)),
|
x => assert_eq!(x, Some(value)),
|
||||||
}
|
}
|
||||||
@@ -104,7 +101,9 @@ impl<'a> FlagsVerifier<'a> {
|
|||||||
// We've reached the def of `live_flags`, so it is no longer live above.
|
// We've reached the def of `live_flags`, so it is no longer live above.
|
||||||
live_val = None;
|
live_val = None;
|
||||||
} else if self.func.dfg.value_type(res).is_flags() {
|
} else if self.func.dfg.value_type(res).is_flags() {
|
||||||
return fatal!(errors, inst, "{} clobbers live CPU flags in {}", res, live);
|
errors
|
||||||
|
.report((inst, format!("{} clobbers live CPU flags in {}", res, live)));
|
||||||
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +115,11 @@ impl<'a> FlagsVerifier<'a> {
|
|||||||
.map_or(false, |c| c.clobbers_flags)
|
.map_or(false, |c| c.clobbers_flags)
|
||||||
&& live_val.is_some()
|
&& live_val.is_some()
|
||||||
{
|
{
|
||||||
return fatal!(errors, inst, "encoding clobbers live CPU flags in {}", live);
|
errors.report((
|
||||||
|
inst,
|
||||||
|
format!("encoding clobbers live CPU flags in {}", live),
|
||||||
|
));
|
||||||
|
return Err(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +167,10 @@ fn merge(
|
|||||||
) -> VerifierStepResult<()> {
|
) -> VerifierStepResult<()> {
|
||||||
if let Some(va) = *a {
|
if let Some(va) = *a {
|
||||||
if b != va {
|
if b != va {
|
||||||
return fatal!(errors, inst, "conflicting live CPU flags: {} and {}", va, b);
|
return errors.fatal((
|
||||||
|
inst,
|
||||||
|
format!("conflicting live CPU flags: {} and {}", va, b),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*a = Some(b);
|
*a = Some(b);
|
||||||
|
|||||||
@@ -54,7 +54,9 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
for &val in self.func.dfg.ebb_params(ebb) {
|
for &val in self.func.dfg.ebb_params(ebb) {
|
||||||
let lr = match self.liveness.get(val) {
|
let lr = match self.liveness.get(val) {
|
||||||
Some(lr) => lr,
|
Some(lr) => lr,
|
||||||
None => return fatal!(errors, ebb, "EBB arg {} has no live range", val),
|
None => {
|
||||||
|
return errors.fatal((ebb, format!("EBB arg {} has no live range", val)))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
self.check_lr(ebb.into(), val, lr, errors)?;
|
self.check_lr(ebb.into(), val, lr, errors)?;
|
||||||
}
|
}
|
||||||
@@ -72,30 +74,32 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
for &val in self.func.dfg.inst_results(inst) {
|
for &val in self.func.dfg.inst_results(inst) {
|
||||||
let lr = match self.liveness.get(val) {
|
let lr = match self.liveness.get(val) {
|
||||||
Some(lr) => lr,
|
Some(lr) => lr,
|
||||||
None => return fatal!(errors, inst, "{} has no live range", val),
|
None => return errors.fatal((inst, format!("{} has no live range", val))),
|
||||||
};
|
};
|
||||||
self.check_lr(inst.into(), val, lr, errors)?;
|
self.check_lr(inst.into(), val, lr, errors)?;
|
||||||
|
|
||||||
if encoding.is_legal() {
|
if encoding.is_legal() {
|
||||||
// A legal instruction is not allowed to define ghost values.
|
// A legal instruction is not allowed to define ghost values.
|
||||||
if lr.affinity.is_unassigned() {
|
if lr.affinity.is_unassigned() {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"{} is a ghost value defined by a real [{}] instruction",
|
format!(
|
||||||
val,
|
"{} is a ghost value defined by a real [{}] instruction",
|
||||||
self.isa.encoding_info().display(encoding)
|
val,
|
||||||
);
|
self.isa.encoding_info().display(encoding)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else if !lr.affinity.is_unassigned() {
|
} else if !lr.affinity.is_unassigned() {
|
||||||
// A non-encoded instruction can only define ghost values.
|
// A non-encoded instruction can only define ghost values.
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"{} is a real {} value defined by a ghost instruction",
|
format!(
|
||||||
val,
|
"{} is a real {} value defined by a ghost instruction",
|
||||||
lr.affinity.display(&self.isa.register_info())
|
val,
|
||||||
);
|
lr.affinity.display(&self.isa.register_info())
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,23 +107,24 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
for &val in self.func.dfg.inst_args(inst) {
|
for &val in self.func.dfg.inst_args(inst) {
|
||||||
let lr = match self.liveness.get(val) {
|
let lr = match self.liveness.get(val) {
|
||||||
Some(lr) => lr,
|
Some(lr) => lr,
|
||||||
None => return fatal!(errors, inst, "{} has no live range", val),
|
None => return errors.fatal((inst, format!("{} has no live range", val))),
|
||||||
};
|
};
|
||||||
|
|
||||||
debug_assert!(self.func.layout.inst_ebb(inst).unwrap() == ebb);
|
debug_assert!(self.func.layout.inst_ebb(inst).unwrap() == ebb);
|
||||||
if !lr.reaches_use(inst, ebb, &self.func.layout) {
|
if !lr.reaches_use(inst, ebb, &self.func.layout) {
|
||||||
return fatal!(errors, inst, "{} is not live at this use", val);
|
return errors.fatal((inst, format!("{} is not live at this use", val)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// A legal instruction is not allowed to depend on ghost values.
|
// A legal instruction is not allowed to depend on ghost values.
|
||||||
if encoding.is_legal() && lr.affinity.is_unassigned() {
|
if encoding.is_legal() && lr.affinity.is_unassigned() {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"{} is a ghost value used by a real [{}] instruction",
|
format!(
|
||||||
val,
|
"{} is a ghost value used by a real [{}] instruction",
|
||||||
self.isa.encoding_info().display(encoding)
|
val,
|
||||||
);
|
self.isa.encoding_info().display(encoding),
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -142,17 +147,14 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
ExpandedProgramPoint::Inst(i) => i.into(),
|
ExpandedProgramPoint::Inst(i) => i.into(),
|
||||||
};
|
};
|
||||||
if lr.def() != def {
|
if lr.def() != def {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
loc,
|
loc,
|
||||||
"Wrong live range def ({}) for {}",
|
format!("Wrong live range def ({}) for {}", lr.def(), val),
|
||||||
lr.def(),
|
));
|
||||||
val
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if lr.is_dead() {
|
if lr.is_dead() {
|
||||||
if !lr.is_local() {
|
if !lr.is_local() {
|
||||||
return fatal!(errors, loc, "Dead live range {} should be local", val);
|
return errors.fatal((loc, format!("Dead live range {} should be local", val)));
|
||||||
} else {
|
} else {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@@ -163,17 +165,14 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
};
|
};
|
||||||
match lr.def_local_end().into() {
|
match lr.def_local_end().into() {
|
||||||
ExpandedProgramPoint::Ebb(e) => {
|
ExpandedProgramPoint::Ebb(e) => {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
loc,
|
loc,
|
||||||
"Def local range for {} can't end at {}",
|
format!("Def local range for {} can't end at {}", val, e),
|
||||||
val,
|
));
|
||||||
e
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
ExpandedProgramPoint::Inst(i) => {
|
ExpandedProgramPoint::Inst(i) => {
|
||||||
if self.func.layout.inst_ebb(i) != Some(def_ebb) {
|
if self.func.layout.inst_ebb(i) != Some(def_ebb) {
|
||||||
return fatal!(errors, loc, "Def local end for {} in wrong ebb", val);
|
return errors.fatal((loc, format!("Def local end for {} in wrong ebb", val)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,25 +180,21 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
// Now check the live-in intervals against the CFG.
|
// Now check the live-in intervals against the CFG.
|
||||||
for (mut ebb, end) in lr.liveins() {
|
for (mut ebb, end) in lr.liveins() {
|
||||||
if !l.is_ebb_inserted(ebb) {
|
if !l.is_ebb_inserted(ebb) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
loc,
|
loc,
|
||||||
"{} livein at {} which is not in the layout",
|
format!("{} livein at {} which is not in the layout", val, ebb),
|
||||||
val,
|
));
|
||||||
ebb
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let end_ebb = match l.inst_ebb(end) {
|
let end_ebb = match l.inst_ebb(end) {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => {
|
None => {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
loc,
|
loc,
|
||||||
"{} livein for {} ends at {} which is not in the layout",
|
format!(
|
||||||
val,
|
"{} livein for {} ends at {} which is not in the layout",
|
||||||
ebb,
|
val, ebb, end
|
||||||
end
|
),
|
||||||
);
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -208,13 +203,10 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
// 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 BasicBlock { inst: pred, ebb } in self.cfg.pred_iter(ebb) {
|
for BasicBlock { inst: pred, ebb } in self.cfg.pred_iter(ebb) {
|
||||||
if !lr.reaches_use(pred, ebb, &self.func.layout) {
|
if !lr.reaches_use(pred, ebb, &self.func.layout) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
pred,
|
pred,
|
||||||
"{} is live in to {} but not live at predecessor",
|
format!("{} is live in to {} but not live at predecessor", val, ebb),
|
||||||
val,
|
));
|
||||||
ebb
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,13 +216,10 @@ impl<'a> LivenessVerifier<'a> {
|
|||||||
ebb = match l.next_ebb(ebb) {
|
ebb = match l.next_ebb(ebb) {
|
||||||
Some(e) => e,
|
Some(e) => e,
|
||||||
None => {
|
None => {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
loc,
|
loc,
|
||||||
"end of {} livein ({}) never reached",
|
format!("end of {} livein ({}) never reached", val, end_ebb),
|
||||||
val,
|
));
|
||||||
end_ebb
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,14 +104,15 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: We could give a better error message here.
|
// TODO: We could give a better error message here.
|
||||||
fatal!(
|
errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"{} constraints not satisfied in: {}\n{}",
|
format!(
|
||||||
self.encinfo.display(enc),
|
"{} constraints not satisfied in: {}\n{}",
|
||||||
self.func.dfg.display_inst(inst, self.isa),
|
self.encinfo.display(enc),
|
||||||
self.func.display(self.isa)
|
self.func.dfg.display_inst(inst, self.isa),
|
||||||
)
|
self.func.display(self.isa),
|
||||||
|
),
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check that the result values produced by a ghost instruction are not assigned a value
|
/// Check that the result values produced by a ghost instruction are not assigned a value
|
||||||
@@ -126,13 +127,14 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
for &res in results {
|
for &res in results {
|
||||||
let loc = self.func.locations[res];
|
let loc = self.func.locations[res];
|
||||||
if loc.is_assigned() {
|
if loc.is_assigned() {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"ghost result {} value must not have a location ({}).",
|
format!(
|
||||||
res,
|
"ghost result {} value must not have a location ({}).",
|
||||||
loc.display(&self.reginfo)
|
res,
|
||||||
);
|
loc.display(&self.reginfo)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,50 +216,51 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
ir::ArgumentLoc::Unassigned => {}
|
ir::ArgumentLoc::Unassigned => {}
|
||||||
ir::ArgumentLoc::Reg(reg) => {
|
ir::ArgumentLoc::Reg(reg) => {
|
||||||
if loc != ir::ValueLoc::Reg(reg) {
|
if loc != ir::ValueLoc::Reg(reg) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"ABI expects {} in {}, got {}",
|
format!(
|
||||||
value,
|
"ABI expects {} in {}, got {}",
|
||||||
abi.location.display(&self.reginfo),
|
value,
|
||||||
loc.display(&self.reginfo)
|
abi.location.display(&self.reginfo),
|
||||||
);
|
loc.display(&self.reginfo),
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir::ArgumentLoc::Stack(offset) => {
|
ir::ArgumentLoc::Stack(offset) => {
|
||||||
if let ir::ValueLoc::Stack(ss) = loc {
|
if let ir::ValueLoc::Stack(ss) = loc {
|
||||||
let slot = &self.func.stack_slots[ss];
|
let slot = &self.func.stack_slots[ss];
|
||||||
if slot.kind != want_kind {
|
if slot.kind != want_kind {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"call argument {} should be in a {} slot, but {} is {}",
|
format!(
|
||||||
value,
|
"call argument {} should be in a {} slot, but {} is {}",
|
||||||
want_kind,
|
value, want_kind, ss, slot.kind
|
||||||
ss,
|
),
|
||||||
slot.kind
|
));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if slot.offset.unwrap() != offset {
|
if slot.offset.unwrap() != offset {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"ABI expects {} at stack offset {}, but {} is at {}",
|
format!(
|
||||||
value,
|
"ABI expects {} at stack offset {}, but {} is at {}",
|
||||||
offset,
|
value,
|
||||||
ss,
|
offset,
|
||||||
slot.offset.unwrap()
|
ss,
|
||||||
);
|
slot.offset.unwrap()
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"ABI expects {} at stack offset {}, got {}",
|
format!(
|
||||||
value,
|
"ABI expects {} at stack offset {}, got {}",
|
||||||
offset,
|
value,
|
||||||
loc.display(&self.reginfo)
|
offset,
|
||||||
);
|
loc.display(&self.reginfo)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -281,21 +284,23 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
|
|
||||||
if let Some(d) = divert.diversion(arg) {
|
if let Some(d) = divert.diversion(arg) {
|
||||||
if d.to != src {
|
if d.to != src {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"inconsistent with current diversion to {}",
|
format!(
|
||||||
d.to.display(&self.reginfo)
|
"inconsistent with current diversion to {}",
|
||||||
);
|
d.to.display(&self.reginfo)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
} else if self.func.locations[arg] != src {
|
} else if self.func.locations[arg] != src {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"inconsistent with global location {} ({})",
|
format!(
|
||||||
self.func.locations[arg].display(&self.reginfo),
|
"inconsistent with global location {} ({})",
|
||||||
self.func.dfg.display_inst(inst, None)
|
self.func.locations[arg].display(&self.reginfo),
|
||||||
);
|
self.func.dfg.display_inst(inst, None)
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
divert.apply(&self.func.dfg[inst]);
|
divert.apply(&self.func.dfg[inst]);
|
||||||
@@ -338,14 +343,15 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
val_to_remove.push(value)
|
val_to_remove.push(value)
|
||||||
}
|
}
|
||||||
} else if lr.is_livein(ebb, &self.func.layout) {
|
} else if lr.is_livein(ebb, &self.func.layout) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"SingleDest: {} is diverted to {} and live in to {}",
|
format!(
|
||||||
value,
|
"SingleDest: {} is diverted to {} and live in to {}",
|
||||||
d.to.display(&self.reginfo),
|
value,
|
||||||
ebb
|
d.to.display(&self.reginfo),
|
||||||
);
|
ebb,
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_after_branch && unique_predecessor {
|
if is_after_branch && unique_predecessor {
|
||||||
@@ -360,26 +366,28 @@ impl<'a> LocationVerifier<'a> {
|
|||||||
let lr = &liveness[value];
|
let lr = &liveness[value];
|
||||||
if let Some(ebb) = ebb {
|
if let Some(ebb) = ebb {
|
||||||
if lr.is_livein(ebb, &self.func.layout) {
|
if lr.is_livein(ebb, &self.func.layout) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"Table.default: {} is diverted to {} and live in to {}",
|
format!(
|
||||||
value,
|
"Table.default: {} is diverted to {} and live in to {}",
|
||||||
d.to.display(&self.reginfo),
|
value,
|
||||||
ebb
|
d.to.display(&self.reginfo),
|
||||||
);
|
ebb,
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for ebb in self.func.jump_tables[jt].iter() {
|
for ebb in self.func.jump_tables[jt].iter() {
|
||||||
if lr.is_livein(*ebb, &self.func.layout) {
|
if lr.is_livein(*ebb, &self.func.layout) {
|
||||||
return fatal!(
|
return errors.fatal((
|
||||||
errors,
|
|
||||||
inst,
|
inst,
|
||||||
"Table.case: {} is diverted to {} and live in to {}",
|
format!(
|
||||||
value,
|
"Table.case: {} is diverted to {} and live in to {}",
|
||||||
d.to.display(&self.reginfo),
|
value,
|
||||||
ebb
|
d.to.display(&self.reginfo),
|
||||||
);
|
ebb,
|
||||||
|
),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user