From 3e5f039333f0206d16cfea3f568d95ce8f9416f7 Mon Sep 17 00:00:00 2001 From: Andrew Brown Date: Wed, 20 Nov 2019 14:17:04 -0800 Subject: [PATCH] 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. --- cranelift/codegen/src/verifier/cssa.rs | 65 +- cranelift/codegen/src/verifier/flags.rs | 24 +- cranelift/codegen/src/verifier/liveness.rs | 111 ++- cranelift/codegen/src/verifier/locations.rs | 158 ++-- cranelift/codegen/src/verifier/mod.rs | 803 ++++++++++---------- 5 files changed, 585 insertions(+), 576 deletions(-) diff --git a/cranelift/codegen/src/verifier/cssa.rs b/cranelift/codegen/src/verifier/cssa.rs index 85c6a638c2..54e88dccf3 100644 --- a/cranelift/codegen/src/verifier/cssa.rs +++ b/cranelift/codegen/src/verifier/cssa.rs @@ -65,13 +65,13 @@ impl<'a> CssaVerifier<'a> { for (idx, &val) in values.iter().enumerate() { 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) { - return fatal!(errors, val, "Detached value in {}", vreg); + return errors.fatal((val, format!("Detached value in {}", vreg))); } 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. @@ -82,29 +82,31 @@ impl<'a> CssaVerifier<'a> { let prev_ebb = self.func.layout.pp_ebb(prev_def); if prev_def == def { - return fatal!( - errors, + return errors.fatal(( val, - "Values {} and {} in {} = {} defined at the same program point", - prev_val, - val, - vreg, - DisplayList(values) - ); + format!( + "Values {} and {} in {} = {} defined at the same program point", + prev_val, + val, + vreg, + DisplayList(values) + ), + )); } // Enforce topological ordering of defs in the virtual register. if self.preorder.dominates(def_ebb, prev_ebb) && self.domtree.dominates(def, prev_def, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( val, - "Value in {} = {} def dominates previous {}", - vreg, - DisplayList(values), - prev_val - ); + format!( + "Value in {} = {} def dominates previous {}", + vreg, + DisplayList(values), + prev_val + ), + )); } } @@ -119,14 +121,15 @@ impl<'a> CssaVerifier<'a> { && self.domtree.dominates(prev_def, def, &self.func.layout) { if self.liveness[prev_val].overlaps_def(def, def_ebb, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( val, - "Value def in {} = {} interferes with {}", - vreg, - DisplayList(values), - prev_val - ); + format!( + "Value def in {} = {} interferes with {}", + vreg, + DisplayList(values), + prev_val + ), + )); } else { break; } @@ -152,13 +155,13 @@ impl<'a> CssaVerifier<'a> { for (&ebb_param, &pred_arg) in ebb_params.iter().zip(pred_args) { if !self.virtregs.same_class(ebb_param, pred_arg) { - return fatal!( - errors, + return errors.fatal(( pred, - "{} and {} must be in the same virtual register", - ebb_param, - pred_arg - ); + format!( + "{} and {} must be in the same virtual register", + ebb_param, pred_arg + ), + )); } } } diff --git a/cranelift/codegen/src/verifier/flags.rs b/cranelift/codegen/src/verifier/flags.rs index d39b6e0487..1748fccf71 100644 --- a/cranelift/codegen/src/verifier/flags.rs +++ b/cranelift/codegen/src/verifier/flags.rs @@ -67,13 +67,10 @@ impl<'a> FlagsVerifier<'a> { } } Some(old) if old != value => { - return fatal!( - errors, + return errors.fatal(( ebb, - "conflicting live-in CPU flags: {} and {}", - old, - value - ); + format!("conflicting live-in CPU flags: {} and {}", old, 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. live_val = None; } 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) && 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<()> { if let Some(va) = *a { 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 { *a = Some(b); diff --git a/cranelift/codegen/src/verifier/liveness.rs b/cranelift/codegen/src/verifier/liveness.rs index 218bb60fdc..4c4940f356 100644 --- a/cranelift/codegen/src/verifier/liveness.rs +++ b/cranelift/codegen/src/verifier/liveness.rs @@ -54,7 +54,9 @@ impl<'a> LivenessVerifier<'a> { for &val in self.func.dfg.ebb_params(ebb) { let lr = match self.liveness.get(val) { 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)?; } @@ -72,30 +74,32 @@ impl<'a> LivenessVerifier<'a> { for &val in self.func.dfg.inst_results(inst) { let lr = match self.liveness.get(val) { 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)?; if encoding.is_legal() { // A legal instruction is not allowed to define ghost values. if lr.affinity.is_unassigned() { - return fatal!( - errors, + return errors.fatal(( inst, - "{} is a ghost value defined by a real [{}] instruction", - val, - self.isa.encoding_info().display(encoding) - ); + format!( + "{} is a ghost value defined by a real [{}] instruction", + val, + self.isa.encoding_info().display(encoding) + ), + )); } } else if !lr.affinity.is_unassigned() { // A non-encoded instruction can only define ghost values. - return fatal!( - errors, + return errors.fatal(( inst, - "{} is a real {} value defined by a ghost instruction", - val, - lr.affinity.display(&self.isa.register_info()) - ); + format!( + "{} is a real {} value defined by a ghost instruction", + 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) { let lr = match self.liveness.get(val) { 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); 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. if encoding.is_legal() && lr.affinity.is_unassigned() { - return fatal!( - errors, + return errors.fatal(( inst, - "{} is a ghost value used by a real [{}] instruction", - val, - self.isa.encoding_info().display(encoding) - ); + format!( + "{} is a ghost value used by a real [{}] instruction", + val, + self.isa.encoding_info().display(encoding), + ), + )); } } } @@ -142,17 +147,14 @@ impl<'a> LivenessVerifier<'a> { ExpandedProgramPoint::Inst(i) => i.into(), }; if lr.def() != def { - return fatal!( - errors, + return errors.fatal(( loc, - "Wrong live range def ({}) for {}", - lr.def(), - val - ); + format!("Wrong live range def ({}) for {}", lr.def(), val), + )); } if lr.is_dead() { 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 { return Ok(()); } @@ -163,17 +165,14 @@ impl<'a> LivenessVerifier<'a> { }; match lr.def_local_end().into() { ExpandedProgramPoint::Ebb(e) => { - return fatal!( - errors, + return errors.fatal(( loc, - "Def local range for {} can't end at {}", - val, - e - ); + format!("Def local range for {} can't end at {}", val, e), + )); } ExpandedProgramPoint::Inst(i) => { 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. for (mut ebb, end) in lr.liveins() { if !l.is_ebb_inserted(ebb) { - return fatal!( - errors, + return errors.fatal(( loc, - "{} livein at {} which is not in the layout", - val, - ebb - ); + format!("{} livein at {} which is not in the layout", val, ebb), + )); } let end_ebb = match l.inst_ebb(end) { Some(e) => e, None => { - return fatal!( - errors, + return errors.fatal(( loc, - "{} livein for {} ends at {} which is not in the layout", - val, - ebb, - end - ); + format!( + "{} livein for {} ends at {} which is not in the layout", + val, ebb, end + ), + )); } }; @@ -208,13 +203,10 @@ impl<'a> LivenessVerifier<'a> { // 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) { if !lr.reaches_use(pred, ebb, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( pred, - "{} is live in to {} but not live at predecessor", - val, - ebb - ); + format!("{} is live in to {} but not live at predecessor", val, ebb), + )); } } @@ -224,13 +216,10 @@ impl<'a> LivenessVerifier<'a> { ebb = match l.next_ebb(ebb) { Some(e) => e, None => { - return fatal!( - errors, + return errors.fatal(( loc, - "end of {} livein ({}) never reached", - val, - end_ebb - ); + format!("end of {} livein ({}) never reached", val, end_ebb), + )); } }; } diff --git a/cranelift/codegen/src/verifier/locations.rs b/cranelift/codegen/src/verifier/locations.rs index 6a32cec0f6..fe180b8e81 100644 --- a/cranelift/codegen/src/verifier/locations.rs +++ b/cranelift/codegen/src/verifier/locations.rs @@ -104,14 +104,15 @@ impl<'a> LocationVerifier<'a> { } // TODO: We could give a better error message here. - fatal!( - errors, + errors.fatal(( inst, - "{} constraints not satisfied in: {}\n{}", - self.encinfo.display(enc), - self.func.dfg.display_inst(inst, self.isa), - self.func.display(self.isa) - ) + format!( + "{} constraints not satisfied in: {}\n{}", + self.encinfo.display(enc), + 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 @@ -126,13 +127,14 @@ impl<'a> LocationVerifier<'a> { for &res in results { let loc = self.func.locations[res]; if loc.is_assigned() { - return fatal!( - errors, + return errors.fatal(( inst, - "ghost result {} value must not have a location ({}).", - res, - loc.display(&self.reginfo) - ); + format!( + "ghost result {} value must not have a location ({}).", + res, + loc.display(&self.reginfo) + ), + )); } } @@ -214,50 +216,51 @@ impl<'a> LocationVerifier<'a> { ir::ArgumentLoc::Unassigned => {} ir::ArgumentLoc::Reg(reg) => { if loc != ir::ValueLoc::Reg(reg) { - return fatal!( - errors, + return errors.fatal(( inst, - "ABI expects {} in {}, got {}", - value, - abi.location.display(&self.reginfo), - loc.display(&self.reginfo) - ); + format!( + "ABI expects {} in {}, got {}", + value, + abi.location.display(&self.reginfo), + loc.display(&self.reginfo), + ), + )); } } ir::ArgumentLoc::Stack(offset) => { if let ir::ValueLoc::Stack(ss) = loc { let slot = &self.func.stack_slots[ss]; if slot.kind != want_kind { - return fatal!( - errors, + return errors.fatal(( inst, - "call argument {} should be in a {} slot, but {} is {}", - value, - want_kind, - ss, - slot.kind - ); + format!( + "call argument {} should be in a {} slot, but {} is {}", + value, want_kind, ss, slot.kind + ), + )); } if slot.offset.unwrap() != offset { - return fatal!( - errors, + return errors.fatal(( inst, - "ABI expects {} at stack offset {}, but {} is at {}", - value, - offset, - ss, - slot.offset.unwrap() - ); + format!( + "ABI expects {} at stack offset {}, but {} is at {}", + value, + offset, + ss, + slot.offset.unwrap() + ), + )); } } else { - return fatal!( - errors, + return errors.fatal(( inst, - "ABI expects {} at stack offset {}, got {}", - value, - offset, - loc.display(&self.reginfo) - ); + format!( + "ABI expects {} at stack offset {}, got {}", + value, + offset, + loc.display(&self.reginfo) + ), + )); } } } @@ -281,21 +284,23 @@ impl<'a> LocationVerifier<'a> { if let Some(d) = divert.diversion(arg) { if d.to != src { - return fatal!( - errors, + return errors.fatal(( inst, - "inconsistent with current diversion to {}", - d.to.display(&self.reginfo) - ); + format!( + "inconsistent with current diversion to {}", + d.to.display(&self.reginfo) + ), + )); } } else if self.func.locations[arg] != src { - return fatal!( - errors, + return errors.fatal(( inst, - "inconsistent with global location {} ({})", - self.func.locations[arg].display(&self.reginfo), - self.func.dfg.display_inst(inst, None) - ); + format!( + "inconsistent with global location {} ({})", + self.func.locations[arg].display(&self.reginfo), + self.func.dfg.display_inst(inst, None) + ), + )); } divert.apply(&self.func.dfg[inst]); @@ -338,14 +343,15 @@ impl<'a> LocationVerifier<'a> { val_to_remove.push(value) } } else if lr.is_livein(ebb, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( inst, - "SingleDest: {} is diverted to {} and live in to {}", - value, - d.to.display(&self.reginfo), - ebb - ); + format!( + "SingleDest: {} is diverted to {} and live in to {}", + value, + d.to.display(&self.reginfo), + ebb, + ), + )); } } if is_after_branch && unique_predecessor { @@ -360,26 +366,28 @@ impl<'a> LocationVerifier<'a> { let lr = &liveness[value]; if let Some(ebb) = ebb { if lr.is_livein(ebb, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( inst, - "Table.default: {} is diverted to {} and live in to {}", - value, - d.to.display(&self.reginfo), - ebb - ); + format!( + "Table.default: {} is diverted to {} and live in to {}", + value, + d.to.display(&self.reginfo), + ebb, + ), + )); } } for ebb in self.func.jump_tables[jt].iter() { if lr.is_livein(*ebb, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( inst, - "Table.case: {} is diverted to {} and live in to {}", - value, - d.to.display(&self.reginfo), - ebb - ); + format!( + "Table.case: {} is diverted to {} and live in to {}", + value, + d.to.display(&self.reginfo), + ebb, + ), + )); } } } diff --git a/cranelift/codegen/src/verifier/mod.rs b/cranelift/codegen/src/verifier/mod.rs index 61b653e469..30990dbf9b 100644 --- a/cranelift/codegen/src/verifier/mod.rs +++ b/cranelift/codegen/src/verifier/mod.rs @@ -85,46 +85,6 @@ pub use self::cssa::verify_cssa; pub use self::liveness::verify_liveness; pub use self::locations::verify_locations; -/// Report an error. -/// -/// The first argument must be a `&mut VerifierErrors` reference, and the following -/// argument defines the location of the error and must implement `Into`. -/// Finally, subsequent arguments will be formatted using `format!()` and set -/// as the error message. -macro_rules! report { - ( $errors: expr, $loc: expr, $msg: tt ) => { - $errors.0.push(crate::verifier::VerifierError { - location: $loc.into(), - context: None, - message: String::from($msg), - }) - }; - - ( $errors: expr, $loc: expr, $fmt: tt, $( $arg: expr ),+ ) => { - $errors.0.push(crate::verifier::VerifierError { - location: $loc.into(), - context: None, - message: format!( $fmt, $( $arg ),+ ), - }) - }; -} - -/// Diagnose a fatal error, and return `Err`. -macro_rules! fatal { - ( $( $arg: expr ),+ ) => ({ - report!( $( $arg ),+ ); - Err(()) - }); -} - -/// Diagnose a non-fatal error, and return `Ok`. -macro_rules! nonfatal { - ( $( $arg: expr ),+ ) => ({ - report!( $( $arg ),+ ); - Ok(()) - }); -} - mod cssa; mod flags; mod liveness; @@ -151,6 +111,50 @@ fn format_context(context: &Option) -> String { } } +/// Convenience converter for making error-reporting less verbose. +/// +/// Converts a tuple of `(location, context, message)` to a `VerifierError`. +/// ``` +/// use cranelift_codegen::verifier::VerifierErrors; +/// use cranelift_codegen::ir::Inst; +/// let mut errors = VerifierErrors::new(); +/// errors.report((Inst::from_u32(42), "v3 = iadd v1, v2", "iadd cannot be used with values of this type")); +/// // note the double parenthenses to use this syntax +/// ``` +impl From<(L, C, M)> for VerifierError +where + L: Into, + C: Into, + M: Into, +{ + fn from(items: (L, C, M)) -> Self { + let (location, context, message) = items; + Self { + location: location.into(), + context: Some(context.into()), + message: message.into(), + } + } +} + +/// Convenience converter for making error-reporting less verbose. +/// +/// Same as above but without `context`. +impl From<(L, M)> for VerifierError +where + L: Into, + M: Into, +{ + fn from(items: (L, M)) -> Self { + let (location, message) = items; + Self { + location: location.into(), + context: None, + message: message.into(), + } + } +} + /// Result of a step in the verification process. /// /// Functions that return `VerifierStepResult<()>` should also take a @@ -202,6 +206,23 @@ impl VerifierErrors { Err(()) } } + + /// Report an error, adding it to the list of errors. + pub fn report(&mut self, error: impl Into) { + self.0.push(error.into()); + } + + /// Report a fatal error and return `Err`. + pub fn fatal(&mut self, error: impl Into) -> VerifierStepResult<()> { + self.report(error); + Err(()) + } + + /// Report a non-fatal error and return `Ok`. + pub fn nonfatal(&mut self, error: impl Into) -> VerifierStepResult<()> { + self.report(error); + Ok(()) + } } impl From> for VerifierErrors { @@ -291,39 +312,10 @@ impl<'a> Verifier<'a> { } } - /// Helper for appending a contextual error to the verifier error list. + /// Determine a contextual error string for an instruction. #[inline] - fn append_error(&self, inst: Inst, errors: &mut VerifierErrors, message: impl Into) { - let location = inst.into(); - let context = Some(self.func.dfg.display_inst(inst, self.isa).to_string()); - let message = message.into(); - errors.0.push(VerifierError { - location, - context, - message, - }); - } - - /// Diagnose a fatal error, and return `Err`. - fn fatal( - &self, - errors: &mut VerifierErrors, - inst: Inst, - message: impl Into, - ) -> VerifierStepResult<()> { - self.append_error(inst, errors, message); - Err(()) - } - - /// Diagnose a non-fatal error, and return `Ok`. - fn nonfatal( - &self, - errors: &mut VerifierErrors, - inst: Inst, - message: impl Into, - ) -> VerifierStepResult<()> { - self.append_error(inst, errors, message); - Ok(()) + fn context(&self, inst: Inst) -> String { + self.func.dfg.display_inst(inst, self.isa).to_string() } // Check for: @@ -344,12 +336,10 @@ impl<'a> Verifier<'a> { | ir::GlobalValueData::IAddImm { base, .. } => { if seen.insert(base).is_some() { if !cycle_seen { - report!( - errors, + errors.report(( gv, - "global value cycle: {}", - DisplayList(seen.as_slice()) - ); + format!("global value cycle: {}", DisplayList(seen.as_slice())), + )); // ensures we don't report the cycle multiple times cycle_seen = true; } @@ -369,29 +359,27 @@ impl<'a> Verifier<'a> { .special_param(ir::ArgumentPurpose::VMContext) .is_none() { - report!(errors, gv, "undeclared vmctx reference {}", gv); + errors.report((gv, format!("undeclared vmctx reference {}", gv))); } } ir::GlobalValueData::IAddImm { base, global_type, .. } => { if !global_type.is_int() { - report!( - errors, + errors.report(( gv, - "iadd_imm global value with non-int type {}", - global_type - ); + format!("iadd_imm global value with non-int type {}", global_type), + )); } else if let Some(isa) = self.isa { let base_type = self.func.global_values[base].global_type(isa); if global_type != base_type { - report!( - errors, + errors.report(( gv, - "iadd_imm type {} differs from operand type {}", - global_type, - base_type - ); + format!( + "iadd_imm type {} differs from operand type {}", + global_type, base_type + ), + )); } } } @@ -400,14 +388,13 @@ impl<'a> Verifier<'a> { let base_type = self.func.global_values[base].global_type(isa); let pointer_type = isa.pointer_type(); if base_type != pointer_type { - report!( - errors, + errors.report(( gv, - "base {} has type {}, which is not the pointer type {}", - base, - base_type, - pointer_type - ); + format!( + "base {} has type {}, which is not the pointer type {}", + base, base_type, pointer_type + ), + )); } } } @@ -424,36 +411,37 @@ impl<'a> Verifier<'a> { for (heap, heap_data) in &self.func.heaps { let base = heap_data.base; if !self.func.global_values.is_valid(base) { - return nonfatal!(errors, heap, "invalid base global value {}", base); + return errors.nonfatal((heap, format!("invalid base global value {}", base))); } let pointer_type = isa.pointer_type(); let base_type = self.func.global_values[base].global_type(isa); if base_type != pointer_type { - report!( - errors, + errors.report(( heap, - "heap base has type {}, which is not the pointer type {}", - base_type, - pointer_type - ); + format!( + "heap base has type {}, which is not the pointer type {}", + base_type, pointer_type + ), + )); } if let ir::HeapStyle::Dynamic { bound_gv, .. } = heap_data.style { if !self.func.global_values.is_valid(bound_gv) { - return nonfatal!(errors, heap, "invalid bound global value {}", bound_gv); + return errors + .nonfatal((heap, format!("invalid bound global value {}", bound_gv))); } let index_type = heap_data.index_type; let bound_type = self.func.global_values[bound_gv].global_type(isa); if index_type != bound_type { - report!( - errors, + errors.report(( heap, - "heap index type {} differs from the type of its bound, {}", - index_type, - bound_type - ); + format!( + "heap index type {} differs from the type of its bound, {}", + index_type, bound_type + ), + )); } } } @@ -467,36 +455,37 @@ impl<'a> Verifier<'a> { for (table, table_data) in &self.func.tables { let base = table_data.base_gv; if !self.func.global_values.is_valid(base) { - return nonfatal!(errors, table, "invalid base global value {}", base); + return errors.nonfatal((table, format!("invalid base global value {}", base))); } let pointer_type = isa.pointer_type(); let base_type = self.func.global_values[base].global_type(isa); if base_type != pointer_type { - report!( - errors, + errors.report(( table, - "table base has type {}, which is not the pointer type {}", - base_type, - pointer_type - ); + format!( + "table base has type {}, which is not the pointer type {}", + base_type, pointer_type + ), + )); } let bound_gv = table_data.bound_gv; if !self.func.global_values.is_valid(bound_gv) { - return nonfatal!(errors, table, "invalid bound global value {}", bound_gv); + return errors + .nonfatal((table, format!("invalid bound global value {}", bound_gv))); } let index_type = table_data.index_type; let bound_type = self.func.global_values[bound_gv].global_type(isa); if index_type != bound_type { - report!( - errors, + errors.report(( table, - "table index type {} differs from the type of its bound, {}", - index_type, - bound_type - ); + format!( + "table index type {} differs from the type of its bound, {}", + index_type, bound_type + ), + )); } } } @@ -519,7 +508,7 @@ impl<'a> Verifier<'a> { fn encodable_as_bb(&self, ebb: Ebb, errors: &mut VerifierErrors) -> VerifierStepResult<()> { match self.func.is_ebb_basic(ebb) { Ok(()) => Ok(()), - Err((inst, message)) => self.fatal(errors, inst, message), + Err((inst, message)) => errors.fatal((inst, self.context(inst), message)), } } @@ -534,31 +523,27 @@ impl<'a> Verifier<'a> { if is_terminator && !is_last_inst { // Terminating instructions only occur at the end of blocks. - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "a terminator instruction was encountered before the end of {}", ebb ), - ); + )); } if is_last_inst && !is_terminator { - return fatal!( - errors, - ebb, - "block does not end in a terminator instruction" - ); + return errors.fatal((ebb, "block does not end in a terminator instruction")); } // Instructions belong to the correct ebb. let inst_ebb = self.func.layout.inst_ebb(inst); if inst_ebb != Some(ebb) { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!("should belong to {} not {:?}", ebb, inst_ebb), - ); + )); } // Parameters belong to the correct ebb. @@ -566,11 +551,11 @@ impl<'a> Verifier<'a> { match self.func.dfg.value_def(arg) { ValueDef::Param(arg_ebb, _) => { if ebb != arg_ebb { - return fatal!(errors, arg, "does not belong to {}", ebb); + return errors.fatal((arg, format!("does not belong to {}", ebb))); } } _ => { - return fatal!(errors, arg, "expected an argument, found a result"); + return errors.fatal((arg, "expected an argument, found a result")); } } } @@ -588,11 +573,11 @@ impl<'a> Verifier<'a> { // The instruction format matches the opcode if inst_data.opcode().format() != InstructionFormat::from(inst_data) { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), "instruction opcode doesn't match instruction format", - ); + )); } let num_fixed_results = inst_data.opcode().constraints().num_fixed_results(); @@ -605,14 +590,14 @@ impl<'a> Verifier<'a> { // All result values for multi-valued instructions are created let got_results = dfg.inst_results(inst).len(); if got_results != total_results { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "expected {} result values, found {}", total_results, got_results, ), - ); + )); } self.verify_entity_references(inst, errors) @@ -631,13 +616,11 @@ impl<'a> Verifier<'a> { // All used values must be attached to something. let original = self.func.dfg.resolve_aliases(arg); if !self.func.dfg.value_is_attached(original) { - report!( - errors, + errors.report(( inst, - "argument {} -> {} is not attached", - arg, - original - ); + self.context(inst), + format!("argument {} -> {} is not attached", arg, original), + )); } } @@ -737,14 +720,18 @@ impl<'a> Verifier<'a> { } => { if let Some(isa) = &self.isa { if !isa.flags().enable_pinned_reg() { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), "GetPinnedReg/SetPinnedReg cannot be used without enable_pinned_reg", - ); + )); } } else { - return self.fatal(errors, inst, "GetPinnedReg/SetPinnedReg need an ISA!"); + return errors.fatal(( + inst, + self.context(inst), + "GetPinnedReg/SetPinnedReg need an ISA!", + )); } } @@ -796,11 +783,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.dfg.ebb_is_valid(e) || !self.func.layout.is_ebb_inserted(e) { - return fatal!(errors, loc, "invalid ebb reference {}", e); + return errors.fatal((loc, format!("invalid ebb reference {}", e))); } if let Some(entry_block) = self.func.layout.entry_block() { if e == entry_block { - return fatal!(errors, loc, "invalid reference to entry ebb {}", e); + return errors.fatal((loc, format!("invalid reference to entry ebb {}", e))); } } Ok(()) @@ -813,7 +800,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.dfg.signatures.is_valid(s) { - self.fatal(errors, inst, format!("invalid signature reference {}", s)) + errors.fatal(( + inst, + self.context(inst), + format!("invalid signature reference {}", s), + )) } else { Ok(()) } @@ -826,7 +817,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.dfg.ext_funcs.is_valid(f) { - self.nonfatal(errors, inst, format!("invalid function reference {}", f)) + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid function reference {}", f), + )) } else { Ok(()) } @@ -839,7 +834,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.stack_slots.is_valid(ss) { - self.nonfatal(errors, inst, format!("invalid stack slot {}", ss)) + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid stack slot {}", ss), + )) } else { Ok(()) } @@ -852,7 +851,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.global_values.is_valid(gv) { - self.nonfatal(errors, inst, format!("invalid global value {}", gv)) + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid global value {}", gv), + )) } else { Ok(()) } @@ -865,7 +868,7 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.heaps.is_valid(heap) { - self.nonfatal(errors, inst, format!("invalid heap {}", heap)) + errors.nonfatal((inst, self.context(inst), format!("invalid heap {}", heap))) } else { Ok(()) } @@ -878,7 +881,7 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.tables.is_valid(table) { - self.nonfatal(errors, inst, format!("invalid table {}", table)) + errors.nonfatal((inst, self.context(inst), format!("invalid table {}", table))) } else { Ok(()) } @@ -891,11 +894,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !l.is_valid(&self.func.dfg.value_lists) { - self.nonfatal( - errors, + errors.nonfatal(( inst, + self.context(inst), format!("invalid value list reference {:?}", l), - ) + )) } else { Ok(()) } @@ -908,7 +911,11 @@ impl<'a> Verifier<'a> { errors: &mut VerifierErrors, ) -> VerifierStepResult<()> { if !self.func.jump_tables.is_valid(j) { - self.nonfatal(errors, inst, format!("invalid jump table reference {}", j)) + errors.nonfatal(( + inst, + self.context(inst), + format!("invalid jump table reference {}", j), + )) } else { Ok(()) } @@ -922,7 +929,11 @@ impl<'a> Verifier<'a> { ) -> VerifierStepResult<()> { let dfg = &self.func.dfg; if !dfg.value_is_valid(v) { - self.nonfatal(errors, loc_inst, format!("invalid value reference {}", v)) + errors.nonfatal(( + loc_inst, + self.context(loc_inst), + format!("invalid value reference {}", v), + )) } else { Ok(()) } @@ -945,23 +956,19 @@ impl<'a> Verifier<'a> { ValueDef::Result(def_inst, _) => { // Value is defined by an instruction that exists. if !dfg.inst_is_valid(def_inst) { - return fatal!( - errors, + return errors.fatal(( loc_inst, - "{} is defined by invalid instruction {}", - v, - def_inst - ); + self.context(loc_inst), + format!("{} 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 fatal!( - errors, + return errors.fatal(( loc_inst, - "{} is defined by {} which has no EBB", - v, - def_inst - ); + self.context(loc_inst), + format!("{} is defined by {} which has no EBB", v, def_inst), + )); } // Defining instruction dominates the instruction that uses the value. if is_reachable { @@ -969,39 +976,37 @@ impl<'a> Verifier<'a> { .expected_domtree .dominates(def_inst, loc_inst, &self.func.layout) { - return fatal!( - errors, + return errors.fatal(( loc_inst, - "uses value {} from non-dominating {}", - v, - def_inst - ); + self.context(loc_inst), + format!("uses value {} from non-dominating {}", v, def_inst), + )); } if def_inst == loc_inst { - return self.fatal( - errors, + return errors.fatal(( loc_inst, + self.context(loc_inst), format!("uses value {} from itself", v), - ); + )); } } } ValueDef::Param(ebb, _) => { // Value is defined by an existing EBB. if !dfg.ebb_is_valid(ebb) { - return self.fatal( - errors, + return errors.fatal(( loc_inst, + self.context(loc_inst), format!("{} is defined by invalid EBB {}", v, ebb), - ); + )); } // Defining EBB is inserted in the layout if !self.func.layout.is_ebb_inserted(ebb) { - return self.fatal( - errors, + return errors.fatal(( loc_inst, + self.context(loc_inst), format!("{} is defined by {} which is not in the layout", v, ebb), - ); + )); } // The defining EBB dominates the instruction using this value. if is_reachable @@ -1009,11 +1014,11 @@ impl<'a> Verifier<'a> { .expected_domtree .dominates(ebb, loc_inst, &self.func.layout) { - return self.fatal( - errors, + return errors.fatal(( loc_inst, + self.context(loc_inst), format!("uses value arg from non-dominating {}", ebb), - ); + )); } } } @@ -1031,22 +1036,20 @@ impl<'a> Verifier<'a> { match self.func.dfg.value_def(v) { ValueDef::Result(def_inst, _) => { if def_inst != loc_inst { - fatal!( - errors, + errors.fatal(( loc_inst, - "instruction result {} is not defined by the instruction", - v - ) + self.context(loc_inst), + format!("instruction result {} is not defined by the instruction", v), + )) } else { Ok(()) } } - ValueDef::Param(_, _) => fatal!( - errors, + ValueDef::Param(_, _) => errors.fatal(( loc_inst, - "instruction result {} is not defined by the instruction", - v - ), + self.context(loc_inst), + format!("instruction result {} is not defined by the instruction", v), + )), } } @@ -1060,15 +1063,14 @@ impl<'a> Verifier<'a> { let value_type = self.func.dfg.value_type(arg); if typ.lane_bits() < value_type.lane_bits() { - self.fatal( - errors, + errors.fatal(( inst, format!( "The bitcast argument {} doesn't fit in a type of {} bits", arg, - typ.lane_bits(), + typ.lane_bits() ), - ) + )) } else { Ok(()) } @@ -1086,23 +1088,21 @@ impl<'a> Verifier<'a> { let expected = self.expected_domtree.idom(ebb); let got = domtree.idom(ebb); if got != expected { - return fatal!( - errors, + return errors.fatal(( ebb, - "invalid domtree, expected idom({}) = {:?}, got {:?}", - ebb, - expected, - got - ); + format!( + "invalid domtree, expected idom({}) = {:?}, got {:?}", + ebb, expected, got + ), + )); } } // We also verify if the postorder defined by `DominatorTree` is sane if domtree.cfg_postorder().len() != self.expected_domtree.cfg_postorder().len() { - return fatal!( - errors, + return errors.fatal(( AnyEntity::Function, - "incorrect number of Ebbs in postorder traversal" - ); + "incorrect number of Ebbs in postorder traversal", + )); } for (index, (&test_ebb, &true_ebb)) in domtree .cfg_postorder() @@ -1111,14 +1111,13 @@ impl<'a> Verifier<'a> { .enumerate() { if test_ebb != true_ebb { - return fatal!( - errors, + return errors.fatal(( test_ebb, - "invalid domtree, postorder ebb number {} should be {}, got {}", - index, - true_ebb, - test_ebb - ); + format!( + "invalid domtree, postorder ebb number {} should be {}, got {}", + index, true_ebb, test_ebb + ), + )); } } // We verify rpo_cmp on pairs of adjacent ebbs in the postorder @@ -1128,13 +1127,13 @@ impl<'a> Verifier<'a> { .rpo_cmp(prev_ebb, next_ebb, &self.func.layout) != Ordering::Greater { - return fatal!( - errors, + return errors.fatal(( next_ebb, - "invalid domtree, rpo_cmp does not says {} is greater than {}", - prev_ebb, - next_ebb - ); + format!( + "invalid domtree, rpo_cmp does not says {} is greater than {}", + prev_ebb, next_ebb + ), + )); } } Ok(()) @@ -1146,26 +1145,26 @@ impl<'a> Verifier<'a> { let ebb_param_count = self.func.dfg.num_ebb_params(ebb); if ebb_param_count != expected_types.len() { - return fatal!( - errors, + return errors.fatal(( ebb, - "entry block parameters ({}) must match function signature ({})", - ebb_param_count, - expected_types.len() - ); + format!( + "entry block parameters ({}) must match function signature ({})", + ebb_param_count, + expected_types.len() + ), + )); } for (i, &arg) in self.func.dfg.ebb_params(ebb).iter().enumerate() { let arg_type = self.func.dfg.value_type(arg); if arg_type != expected_types[i].value_type { - report!( - errors, + errors.report(( ebb, - "entry block parameter {} expected to have type {}, got {}", - i, - expected_types[i], - arg_type - ); + format!( + "entry block parameter {} expected to have type {}, got {}", + i, expected_types[i], arg_type + ), + )); } } } @@ -1182,12 +1181,11 @@ impl<'a> Verifier<'a> { let ctrl_type = self.func.dfg.ctrl_typevar(inst); if !value_typeset.contains(ctrl_type) { - report!( - errors, + errors.report(( inst, - "has an invalid controlling type {}", - ctrl_type - ); + self.context(inst), + format!("has an invalid controlling type {}", ctrl_type), + )); } ctrl_type @@ -1222,25 +1220,32 @@ impl<'a> Verifier<'a> { let expected_type = self.func.dfg.compute_result_type(inst, i, ctrl_type); if let Some(expected_type) = expected_type { if result_type != expected_type { - report!( - errors, + errors.report(( inst, - "expected result {} ({}) to have type {}, found {}", - i, - result, - expected_type, - result_type - ); + self.context(inst), + format!( + "expected result {} ({}) to have type {}, found {}", + i, result, expected_type, result_type + ), + )); } } else { - return self.nonfatal(errors, inst, "has more result values than expected"); + return errors.nonfatal(( + inst, + self.context(inst), + "has more result values than expected", + )); } i += 1; } // There aren't any more result types left. if self.func.dfg.compute_result_type(inst, i, ctrl_type) != None { - return self.nonfatal(errors, inst, "has fewer result values than expected"); + return errors.nonfatal(( + inst, + self.context(inst), + "has fewer result values than expected", + )); } Ok(()) } @@ -1258,28 +1263,26 @@ impl<'a> Verifier<'a> { match constraints.value_argument_constraint(i, ctrl_type) { ResolvedConstraint::Bound(expected_type) => { if arg_type != expected_type { - report!( - errors, + errors.report(( inst, - "arg {} ({}) has type {}, expected {}", - i, - arg, - arg_type, - expected_type - ); + self.context(inst), + format!( + "arg {} ({}) has type {}, expected {}", + i, arg, arg_type, expected_type + ), + )); } } ResolvedConstraint::Free(type_set) => { if !type_set.contains(arg_type) { - report!( - errors, + errors.report(( inst, - "arg {} ({}) with type {} failed to satisfy type set {:?}", - i, - arg, - arg_type, - type_set - ); + self.context(inst), + format!( + "arg {} ({}) with type {} failed to satisfy type set {:?}", + i, arg, arg_type, type_set + ), + )); } } } @@ -1306,27 +1309,27 @@ impl<'a> Verifier<'a> { if let Some(ebb) = ebb { let arg_count = self.func.dfg.num_ebb_params(ebb); if arg_count != 0 { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "takes no arguments, but had target {} with {} arguments", ebb, arg_count, ), - ); + )); } } for ebb in self.func.jump_tables[table].iter() { let arg_count = self.func.dfg.num_ebb_params(*ebb); if arg_count != 0 { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "takes no arguments, but had target {} with {} arguments", ebb, arg_count, ), - ); + )); } } } @@ -1374,29 +1377,28 @@ impl<'a> Verifier<'a> { let arg = variable_args[i]; let arg_type = self.func.dfg.value_type(arg); if expected_type != arg_type { - report!( - errors, + errors.report(( inst, - "arg {} ({}) has type {}, expected {}", - i, - variable_args[i], - arg_type, - expected_type - ); + self.context(inst), + format!( + "arg {} ({}) has type {}, expected {}", + i, variable_args[i], arg_type, expected_type + ), + )); } i += 1; } if i != variable_args.len() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "mismatched argument count for `{}`: got {}, expected {}", self.func.dfg.display_inst(inst, None), variable_args.len(), i, ), - ); + )); } Ok(()) } @@ -1425,46 +1427,46 @@ impl<'a> Verifier<'a> { self.verify_stack_slot(inst, ss, errors)?; let slot = &self.func.stack_slots[ss]; if slot.kind != StackSlotKind::OutgoingArg { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "Outgoing stack argument {} in wrong stack slot: {} = {}", arg, ss, slot, ), - ); + )); } if slot.offset != Some(offset) { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "Outgoing stack argument {} should have offset {}: {} = {}", arg, offset, ss, slot, ), - ); + )); } if slot.size != abi.value_type.bytes() { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "Outgoing stack argument {} wrong size for {}: {} = {}", arg, abi.value_type, ss, slot, ), - ); + )); } } else { let reginfo = self.isa.map(|i| i.register_info()); - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "Outgoing stack argument {} in wrong location: {}", arg, - arg_loc.display(reginfo.as_ref()), + arg_loc.display(reginfo.as_ref()) ), - ); + )); } } } @@ -1476,24 +1478,23 @@ impl<'a> Verifier<'a> { let args = self.func.dfg.inst_variable_args(inst); let expected_types = &self.func.signature.returns; if args.len() != expected_types.len() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), "arguments of return must match function signature", - ); + )); } for (i, (&arg, &expected_type)) in args.iter().zip(expected_types).enumerate() { let arg_type = self.func.dfg.value_type(arg); if arg_type != expected_type.value_type { - report!( - errors, + errors.report(( inst, - "arg {} ({}) has type {}, must match function signature of {}", - i, - arg, - arg_type, - expected_type - ); + self.context(inst), + format!( + "arg {} ({}) has type {}, must match function signature of {}", + i, arg, arg_type, expected_type + ), + )); } } } @@ -1514,46 +1515,46 @@ impl<'a> Verifier<'a> { match opcode { Opcode::Bextend | Opcode::Uextend | Opcode::Sextend | Opcode::Fpromote => { if arg_type.lane_count() != ctrl_type.lane_count() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "input {} and output {} must have same number of lanes", arg_type, ctrl_type, ), - ); + )); } if arg_type.lane_bits() >= ctrl_type.lane_bits() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "input {} must be smaller than output {}", arg_type, ctrl_type, ), - ); + )); } } Opcode::Breduce | Opcode::Ireduce | Opcode::Fdemote => { if arg_type.lane_count() != ctrl_type.lane_count() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "input {} and output {} must have same number of lanes", arg_type, ctrl_type, ), - ); + )); } if arg_type.lane_bits() <= ctrl_type.lane_bits() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "input {} must be larger than output {}", arg_type, ctrl_type, ), - ); + )); } } _ => {} @@ -1563,28 +1564,28 @@ impl<'a> Verifier<'a> { let index_type = self.func.dfg.value_type(arg); let heap_index_type = self.func.heaps[heap].index_type; if index_type != heap_index_type { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "index type {} differs from heap index type {}", index_type, heap_index_type, ), - ); + )); } } ir::InstructionData::TableAddr { table, arg, .. } => { let index_type = self.func.dfg.value_type(arg); let table_index_type = self.func.tables[table].index_type; if index_type != table_index_type { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "index type {} differs from table index type {}", index_type, table_index_type, ), - ); + )); } } ir::InstructionData::UnaryGlobalValue { global_value, .. } => { @@ -1592,13 +1593,12 @@ impl<'a> Verifier<'a> { let inst_type = self.func.dfg.value_type(self.func.dfg.first_result(inst)); let global_type = self.func.global_values[global_value].global_type(isa); if inst_type != global_type { - return self.nonfatal( - errors, - inst, + return errors.nonfatal(( + inst, self.context(inst), format!( "global_value instruction with type {} references global value with type {}", inst_type, global_type - ), + )), ); } } @@ -1620,11 +1620,19 @@ impl<'a> Verifier<'a> { { let dst_vals = self.func.dfg.inst_results(inst); if dst_vals.len() != 1 { - return self.fatal(errors, inst, "copy_nop must produce exactly one result"); + return errors.fatal(( + inst, + self.context(inst), + "copy_nop must produce exactly one result", + )); } let dst_val = dst_vals[0]; if self.func.dfg.value_type(dst_val) != self.func.dfg.value_type(arg) { - return self.fatal(errors, inst, "copy_nop src and dst types must be the same"); + return errors.fatal(( + inst, + self.context(inst), + "copy_nop src and dst types must be the same", + )); } let src_loc = self.func.locations[arg]; let dst_loc = self.func.locations[dst_val]; @@ -1633,14 +1641,14 @@ impl<'a> Verifier<'a> { _ => false, }; if !locs_ok { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), format!( "copy_nop must refer to identical stack slots, but found {:?} vs {:?}", src_loc, dst_loc, ), - ); + )); } } Ok(()) @@ -1662,23 +1670,19 @@ impl<'a> Verifier<'a> { let missing_succs: Vec = expected_succs.difference(&got_succs).cloned().collect(); if !missing_succs.is_empty() { - report!( - errors, + errors.report(( ebb, - "cfg lacked the following successor(s) {:?}", - missing_succs - ); + format!("cfg lacked the following successor(s) {:?}", missing_succs), + )); continue; } let excess_succs: Vec = got_succs.difference(&expected_succs).cloned().collect(); if !excess_succs.is_empty() { - report!( - errors, + errors.report(( ebb, - "cfg had unexpected successor(s) {:?}", - excess_succs - ); + format!("cfg had unexpected successor(s) {:?}", excess_succs), + )); continue; } @@ -1691,23 +1695,22 @@ impl<'a> Verifier<'a> { let missing_preds: Vec = expected_preds.difference(&got_preds).cloned().collect(); if !missing_preds.is_empty() { - report!( - errors, + errors.report(( ebb, - "cfg lacked the following predecessor(s) {:?}", - missing_preds - ); + format!( + "cfg lacked the following predecessor(s) {:?}", + missing_preds + ), + )); continue; } let excess_preds: Vec = got_preds.difference(&expected_preds).cloned().collect(); if !excess_preds.is_empty() { - report!( - errors, + errors.report(( ebb, - "cfg had unexpected predecessor(s) {:?}", - excess_preds - ); + format!("cfg had unexpected predecessor(s) {:?}", excess_preds), + )); continue; } @@ -1738,14 +1741,14 @@ impl<'a> Verifier<'a> { let encoding = self.func.encodings[inst]; if encoding.is_legal() { if self.func.dfg[inst].opcode().is_ghost() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "Ghost instruction has an encoding: {}", isa.encoding_info().display(encoding), ), - ); + )); } let mut encodings = isa @@ -1757,14 +1760,14 @@ impl<'a> Verifier<'a> { .peekable(); if encodings.peek().is_none() { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "Instruction failed to re-encode {}", isa.encoding_info().display(encoding), ), - ); + )); } let has_valid_encoding = encodings.any(|possible_enc| encoding == possible_enc); @@ -1787,16 +1790,16 @@ impl<'a> Verifier<'a> { .unwrap(); } - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( "encoding {} should be {}{}", isa.encoding_info().display(encoding), if multiple_encodings { "one of: " } else { "" }, possible_encodings, ), - ); + )); } return Ok(()); } @@ -1835,18 +1838,22 @@ impl<'a> Verifier<'a> { // Provide the ISA default encoding as a hint. match self.func.encode(inst, isa) { Ok(enc) => { - return self.nonfatal( - errors, + return errors.nonfatal(( inst, + self.context(inst), format!( - "{} must have an encoding (e.g., {})", + "{} must have an encoding (e.g., {})))", text, isa.encoding_info().display(enc), ), - ); + )); } Err(_) => { - return self.nonfatal(errors, inst, format!("{} must have an encoding", text)) + return errors.nonfatal(( + inst, + self.context(inst), + format!("{} must have an encoding", text), + )) } } } @@ -1865,11 +1872,11 @@ impl<'a> Verifier<'a> { ir::InstructionData::Store { flags, .. } | ir::InstructionData::StoreComplex { flags, .. } => { if flags.readonly() { - self.fatal( - errors, + errors.fatal(( inst, + self.context(inst), "A store instruction cannot have the `readonly` MemFlag", - ) + )) } else { Ok(()) } @@ -1890,11 +1897,11 @@ impl<'a> Verifier<'a> { // the ExtractLane/InsertLane formats. let ty = self.func.dfg.value_type(arg); if u16::from(lane) >= ty.lane_count() { - self.fatal( - errors, + errors.fatal(( inst, + self.context(inst), format!("The lane {} does not index into the type {}", lane, ty,), - ) + )) } else { Ok(()) } @@ -1911,11 +1918,11 @@ impl<'a> Verifier<'a> { if let Some(isa) = self.isa { if !isa.flags().enable_safepoints() && self.func.dfg[inst].opcode() == Opcode::Safepoint { - return self.fatal( - errors, + return errors.fatal(( inst, + self.context(inst), "safepoint instruction cannot be used when it is not enabled.", - ); + )); } } Ok(()) @@ -1929,12 +1936,10 @@ impl<'a> Verifier<'a> { .enumerate() .filter(|(_, ¶m)| param.value_type == types::INVALID) .for_each(|(i, _)| { - report!( - errors, + errors.report(( AnyEntity::Function, - "Parameter at position {} has an invalid type", - i - ); + format!("Parameter at position {} has an invalid type", i), + )); }); self.func @@ -1944,12 +1949,10 @@ impl<'a> Verifier<'a> { .enumerate() .filter(|(_, &ret)| ret.value_type == types::INVALID) .for_each(|(i, _)| { - report!( - errors, + errors.report(( AnyEntity::Function, - "Return value at position {} has an invalid type", - i - ) + format!("Return value at position {} has an invalid type", i), + )) }); if errors.has_error() {