Files
wasmtime/cranelift/codegen/src/print_errors.rs
Ryan Hunt 832666c45e Mass rename Ebb and relatives to Block (#1365)
* Manually rename BasicBlock to BlockPredecessor

BasicBlock is a pair of (Ebb, Inst) that is used to represent the
basic block subcomponent of an Ebb that is a predecessor to an Ebb.

Eventually we will be able to remove this struct, but for now it
makes sense to give it a non-conflicting name so that we can start
to transition Ebb to represent a basic block.

I have not updated any comments that refer to BasicBlock, as
eventually we will remove BlockPredecessor and replace with Block,
which is a basic block, so the comments will become correct.

* Manually rename SSABuilder block types to avoid conflict

SSABuilder has its own Block and BlockData types. These along with
associated identifier will cause conflicts in a later commit, so
they are renamed to be more verbose here.

* Automatically rename 'Ebb' to 'Block' in *.rs

* Automatically rename 'EBB' to 'block' in *.rs

* Automatically rename 'ebb' to 'block' in *.rs

* Automatically rename 'extended basic block' to 'basic block' in *.rs

* Automatically rename 'an basic block' to 'a basic block' in *.rs

* Manually update comment for `Block`

`Block`'s wikipedia article required an update.

* Automatically rename 'an `Block`' to 'a `Block`' in *.rs

* Automatically rename 'extended_basic_block' to 'basic_block' in *.rs

* Automatically rename 'ebb' to 'block' in *.clif

* Manually rename clif constant that contains 'ebb' as substring to avoid conflict

* Automatically rename filecheck uses of 'EBB' to 'BB'

'regex: EBB' -> 'regex: BB'
'$EBB' -> '$BB'

* Automatically rename 'EBB' 'Ebb' to 'block' in *.clif

* Automatically rename 'an block' to 'a block' in *.clif

* Fix broken testcase when function name length increases

Test function names are limited to 16 characters. This causes
the new longer name to be truncated and fail a filecheck test. An
outdated comment was also fixed.
2020-02-07 10:46:47 -06:00

228 lines
5.9 KiB
Rust

//! 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()
}
}