summaryrefslogtreecommitdiffstats
path: root/third_party/rust/cranelift-codegen/src/print_errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/cranelift-codegen/src/print_errors.rs')
-rw-r--r--third_party/rust/cranelift-codegen/src/print_errors.rs227
1 files changed, 227 insertions, 0 deletions
diff --git a/third_party/rust/cranelift-codegen/src/print_errors.rs b/third_party/rust/cranelift-codegen/src/print_errors.rs
new file mode 100644
index 0000000000..e4f6234ebd
--- /dev/null
+++ b/third_party/rust/cranelift-codegen/src/print_errors.rs
@@ -0,0 +1,227 @@
+//! Utility routines for pretty-printing error messages.
+
+use crate::entity::SecondaryMap;
+use crate::ir;
+use crate::ir::entities::{AnyEntity, Block, Inst, Value};
+use crate::ir::function::Function;
+use crate::isa::TargetIsa;
+use crate::result::CodegenError;
+use crate::verifier::{VerifierError, VerifierErrors};
+use crate::write::{decorate_function, FuncWriter, PlainWriter};
+use alloc::boxed::Box;
+use alloc::string::{String, ToString};
+use alloc::vec::Vec;
+use core::fmt;
+use core::fmt::Write;
+
+/// Pretty-print a verifier error.
+pub fn pretty_verifier_error<'a>(
+ func: &ir::Function,
+ isa: Option<&dyn TargetIsa>,
+ func_w: Option<Box<dyn FuncWriter + 'a>>,
+ errors: VerifierErrors,
+) -> String {
+ let mut errors = errors.0;
+ let mut w = String::new();
+ let num_errors = errors.len();
+
+ decorate_function(
+ &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors),
+ &mut w,
+ func,
+ &isa.into(),
+ )
+ .unwrap();
+
+ writeln!(
+ w,
+ "\n; {} verifier error{} detected (see above). Compilation aborted.",
+ num_errors,
+ if num_errors == 1 { "" } else { "s" }
+ )
+ .unwrap();
+
+ w
+}
+
+struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
+
+impl<'a> FuncWriter for PrettyVerifierError<'a> {
+ fn write_block_header(
+ &mut self,
+ w: &mut dyn Write,
+ func: &Function,
+ isa: Option<&dyn TargetIsa>,
+ block: Block,
+ indent: usize,
+ ) -> fmt::Result {
+ pretty_block_header_error(w, func, isa, block, indent, &mut *self.0, self.1)
+ }
+
+ fn write_instruction(
+ &mut self,
+ w: &mut dyn Write,
+ func: &Function,
+ aliases: &SecondaryMap<Value, Vec<Value>>,
+ isa: Option<&dyn TargetIsa>,
+ inst: Inst,
+ indent: usize,
+ ) -> fmt::Result {
+ pretty_instruction_error(w, func, aliases, isa, inst, indent, &mut *self.0, self.1)
+ }
+
+ fn write_entity_definition(
+ &mut self,
+ w: &mut dyn Write,
+ func: &Function,
+ entity: AnyEntity,
+ value: &dyn fmt::Display,
+ ) -> fmt::Result {
+ pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
+ }
+}
+
+/// Pretty-print a function verifier error for a given block.
+fn pretty_block_header_error(
+ w: &mut dyn Write,
+ func: &Function,
+ isa: Option<&dyn TargetIsa>,
+ cur_block: Block,
+ indent: usize,
+ func_w: &mut dyn FuncWriter,
+ errors: &mut Vec<VerifierError>,
+) -> fmt::Result {
+ let mut s = String::new();
+ func_w.write_block_header(&mut s, func, isa, cur_block, indent)?;
+ write!(w, "{}", s)?;
+
+ // TODO: Use drain_filter here when it gets stabilized
+ let mut i = 0;
+ let mut printed_error = false;
+ while i != errors.len() {
+ match errors[i].location {
+ ir::entities::AnyEntity::Block(block) if block == cur_block => {
+ if !printed_error {
+ print_arrow(w, &s)?;
+ printed_error = true;
+ }
+ let err = errors.remove(i);
+ print_error(w, err)?;
+ }
+ _ => i += 1,
+ }
+ }
+
+ if printed_error {
+ w.write_char('\n')?;
+ }
+
+ Ok(())
+}
+
+/// Pretty-print a function verifier error for a given instruction.
+fn pretty_instruction_error(
+ w: &mut dyn Write,
+ func: &Function,
+ aliases: &SecondaryMap<Value, Vec<Value>>,
+ isa: Option<&dyn TargetIsa>,
+ cur_inst: Inst,
+ indent: usize,
+ func_w: &mut dyn FuncWriter,
+ errors: &mut Vec<VerifierError>,
+) -> fmt::Result {
+ let mut s = String::new();
+ func_w.write_instruction(&mut s, func, aliases, isa, cur_inst, indent)?;
+ write!(w, "{}", s)?;
+
+ // TODO: Use drain_filter here when it gets stabilized
+ let mut i = 0;
+ let mut printed_error = false;
+ while i != errors.len() {
+ match errors[i].location {
+ ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
+ if !printed_error {
+ print_arrow(w, &s)?;
+ printed_error = true;
+ }
+ let err = errors.remove(i);
+ print_error(w, err)?;
+ }
+ _ => i += 1,
+ }
+ }
+
+ if printed_error {
+ w.write_char('\n')?;
+ }
+
+ Ok(())
+}
+
+fn pretty_preamble_error(
+ w: &mut dyn Write,
+ func: &Function,
+ entity: AnyEntity,
+ value: &dyn fmt::Display,
+ func_w: &mut dyn FuncWriter,
+ errors: &mut Vec<VerifierError>,
+) -> fmt::Result {
+ let mut s = String::new();
+ func_w.write_entity_definition(&mut s, func, entity, value)?;
+ write!(w, "{}", s)?;
+
+ // TODO: Use drain_filter here when it gets stabilized
+ let mut i = 0;
+ let mut printed_error = false;
+ while i != errors.len() {
+ if entity == errors[i].location {
+ if !printed_error {
+ print_arrow(w, &s)?;
+ printed_error = true;
+ }
+ let err = errors.remove(i);
+ print_error(w, err)?;
+ } else {
+ i += 1
+ }
+ }
+
+ if printed_error {
+ w.write_char('\n')?;
+ }
+
+ Ok(())
+}
+
+/// Prints:
+/// ; ^~~~~~
+fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result {
+ write!(w, ";")?;
+
+ let indent = entity.len() - entity.trim_start().len();
+ if indent != 0 {
+ write!(w, "{1:0$}^", indent - 1, "")?;
+ }
+
+ for _ in 0..entity.trim().len() - 1 {
+ write!(w, "~")?;
+ }
+
+ writeln!(w)
+}
+
+/// Prints:
+/// ; error: [ERROR BODY]
+fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
+ writeln!(w, "; error: {}", err.to_string())?;
+ Ok(())
+}
+
+/// Pretty-print a Cranelift error.
+pub fn pretty_error(func: &ir::Function, isa: Option<&dyn TargetIsa>, err: CodegenError) -> String {
+ if let CodegenError::Verifier(e) = err {
+ pretty_verifier_error(func, isa, None, e)
+ } else {
+ err.to_string()
+ }
+}