Pretty printing preamble errors. (#472)

* Pretty printing preamble errors.
This commit is contained in:
Grégoire Geis
2018-08-27 18:38:44 +02:00
committed by Dan Gohman
parent 0a65089a36
commit 8e74a4f8fc
2 changed files with 108 additions and 86 deletions

View File

@@ -1,9 +1,9 @@
//! Utility routines for pretty-printing error messages. //! Utility routines for pretty-printing error messages.
use ir; use ir;
use ir::entities::Inst; use ir::entities::{AnyEntity, Inst};
use ir::function::Function; use ir::function::Function;
use isa::{RegInfo, TargetIsa}; use isa::TargetIsa;
use result::CodegenError; use result::CodegenError;
use std::boxed::Box; use std::boxed::Box;
use std::fmt; use std::fmt;
@@ -23,25 +23,6 @@ pub fn pretty_verifier_error<'a>(
let mut errors = errors.0; let mut errors = errors.0;
let mut w = String::new(); let mut w = String::new();
// TODO: Use drain_filter here when it gets stabilized
let mut i = 0;
let mut wrote_error = false;
while i != errors.len() {
if let ir::entities::AnyEntity::Inst(_) = errors[i].location {
i += 1;
} else {
let err = errors.remove(i);
writeln!(w, "verifier at {}", err).unwrap();
wrote_error = true;
}
}
if wrote_error {
w.push('\n');
}
decorate_function( decorate_function(
&mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), &mut errors), &mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), &mut errors),
&mut w, &mut w,
@@ -62,21 +43,22 @@ impl<'a> FuncWriter for PrettyVerifierError<'a> {
inst: Inst, inst: Inst,
indent: usize, indent: usize,
) -> fmt::Result { ) -> fmt::Result {
pretty_function_error(w, func, isa, inst, indent, &mut *self.0, self.1) pretty_instruction_error(w, func, isa, inst, indent, &mut *self.0, self.1)
} }
fn write_preamble( fn write_entity_definition(
&mut self, &mut self,
w: &mut Write, w: &mut Write,
func: &Function, func: &Function,
regs: Option<&RegInfo>, entity: AnyEntity,
) -> Result<bool, fmt::Error> { value: &fmt::Display,
self.0.write_preamble(w, func, regs) ) -> fmt::Result {
pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
} }
} }
/// Pretty-print a function verifier error. /// Pretty-print a function verifier error.
fn pretty_function_error( fn pretty_instruction_error(
w: &mut Write, w: &mut Write,
func: &Function, func: &Function,
isa: Option<&TargetIsa>, isa: Option<&TargetIsa>,
@@ -125,6 +107,48 @@ fn pretty_function_error(
Ok(()) Ok(())
} }
fn pretty_preamble_error(
w: &mut Write,
func: &Function,
entity: AnyEntity,
value: &fmt::Display,
func_w: &mut FuncWriter,
errors: &mut Vec<VerifierError>,
) -> fmt::Result {
// TODO: Use drain_filter here when it gets stabilized
let indent = 4;
let mut i = 0;
let mut printed_entity = false;
while i != errors.len() {
if entity == errors[i].location {
let err = errors.remove(i);
if !printed_entity {
func_w.write_entity_definition(w, func, entity, value)?;
printed_entity = true;
}
write!(w, "{1:0$}^", indent, "")?;
for _c in entity.to_string().chars() {
write!(w, "~")?;
}
writeln!(w, " verifier {}", err.to_string())?;
} else {
i += 1
}
}
if printed_entity {
w.write_char('\n')?;
} else {
func_w.write_entity_definition(w, func, entity, value)?;
}
Ok(())
}
/// Pretty-print a Cranelift error. /// Pretty-print a Cranelift error.
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String { pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
if let CodegenError::Verifier(e) = err { if let CodegenError::Verifier(e) = err {

View File

@@ -3,15 +3,16 @@
//! The `write` module provides the `write_function` function which converts an IR `Function` to an //! The `write` module provides the `write_function` function which converts an IR `Function` to an
//! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate. //! equivalent textual form. This textual form can be read back by the `cranelift-reader` crate.
use ir::entities::AnyEntity;
use ir::{DataFlowGraph, Ebb, Function, Inst, SigRef, Type, Value, ValueDef}; use ir::{DataFlowGraph, Ebb, Function, Inst, SigRef, Type, Value, ValueDef};
use isa::{RegInfo, TargetIsa}; use isa::{RegInfo, TargetIsa};
use packed_option::ReservedValue; use packed_option::ReservedValue;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use std::string::String; use std::string::String;
/// A `FuncWriter` is used to decorate functions during printing /// A `FuncWriter` used to decorate functions during printing.
pub trait FuncWriter { pub trait FuncWriter {
/// Write the given inst to w /// Write the given `inst` to `w`.
fn write_instruction( fn write_instruction(
&mut self, &mut self,
w: &mut Write, w: &mut Write,
@@ -21,16 +22,66 @@ pub trait FuncWriter {
ident: usize, ident: usize,
) -> fmt::Result; ) -> fmt::Result;
/// Write the preamble to w /// Write the preamble to `w`. By default, this uses `write_entity_definition`.
fn write_preamble( fn write_preamble(
&mut self, &mut self,
w: &mut Write, w: &mut Write,
func: &Function, func: &Function,
regs: Option<&RegInfo>, regs: Option<&RegInfo>,
) -> Result<bool, fmt::Error>; ) -> Result<bool, fmt::Error> {
let mut any = false;
for (ss, slot) in func.stack_slots.iter() {
any = true;
self.write_entity_definition(w, func, ss.into(), slot)?;
}
for (gv, gv_data) in &func.global_values {
any = true;
self.write_entity_definition(w, func, gv.into(), gv_data)?;
}
for (heap, heap_data) in &func.heaps {
any = true;
self.write_entity_definition(w, func, heap.into(), heap_data)?;
}
// Write out all signatures before functions since function declarations can refer to
// signatures.
for (sig, sig_data) in &func.dfg.signatures {
any = true;
self.write_entity_definition(w, func, sig.into(), &sig_data.display(regs))?;
}
for (fnref, ext_func) in &func.dfg.ext_funcs {
any = true;
if ext_func.signature != SigRef::reserved_value() {
self.write_entity_definition(w, func, fnref.into(), ext_func)?;
}
}
for (jt, jt_data) in &func.jump_tables {
any = true;
self.write_entity_definition(w, func, jt.into(), jt_data)?;
}
Ok(any)
}
/// Write an entity definition defined in the preamble to `w`.
#[allow(unused_variables)]
fn write_entity_definition(
&mut self,
w: &mut Write,
func: &Function,
entity: AnyEntity,
value: &fmt::Display,
) -> fmt::Result {
writeln!(w, " {} = {}", entity, value)
}
} }
/// A `PlainWriter` doesn't decorate the function /// A `PlainWriter` that doesn't decorate the function.
pub struct PlainWriter; pub struct PlainWriter;
impl FuncWriter for PlainWriter { impl FuncWriter for PlainWriter {
@@ -44,15 +95,6 @@ impl FuncWriter for PlainWriter {
) -> fmt::Result { ) -> fmt::Result {
write_instruction(w, func, isa, inst, indent) write_instruction(w, func, isa, inst, indent)
} }
fn write_preamble(
&mut self,
w: &mut Write,
func: &Function,
regs: Option<&RegInfo>,
) -> Result<bool, fmt::Error> {
write_preamble(w, func, regs)
}
} }
/// Write `func` to `w` as equivalent text. /// Write `func` to `w` as equivalent text.
@@ -61,7 +103,7 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) -
decorate_function(&mut PlainWriter, w, func, isa) decorate_function(&mut PlainWriter, w, func, isa)
} }
/// Writes 'func' to 'w' as text. /// Writes `func` to `w` as text.
/// write_function_plain is passed as 'closure' to print instructions as text. /// write_function_plain is passed as 'closure' to print instructions as text.
/// pretty_function_error is passed as 'closure' to add error decoration. /// pretty_function_error is passed as 'closure' to add error decoration.
pub fn decorate_function<FW: FuncWriter>( pub fn decorate_function<FW: FuncWriter>(
@@ -95,50 +137,6 @@ fn write_spec(w: &mut Write, func: &Function, regs: Option<&RegInfo>) -> fmt::Re
write!(w, "{}{}", func.name, func.signature.display(regs)) write!(w, "{}{}", func.name, func.signature.display(regs))
} }
fn write_preamble(
w: &mut Write,
func: &Function,
regs: Option<&RegInfo>,
) -> Result<bool, fmt::Error> {
let mut any = false;
for (ss, slot) in func.stack_slots.iter() {
any = true;
writeln!(w, " {} = {}", ss, slot)?;
}
for (gv, gv_data) in &func.global_values {
any = true;
writeln!(w, " {} = {}", gv, gv_data)?;
}
for (heap, heap_data) in &func.heaps {
any = true;
writeln!(w, " {} = {}", heap, heap_data)?;
}
// Write out all signatures before functions since function declarations can refer to
// signatures.
for (sig, sig_data) in &func.dfg.signatures {
any = true;
writeln!(w, " {} = {}", sig, sig_data.display(regs))?;
}
for (fnref, ext_func) in &func.dfg.ext_funcs {
any = true;
if ext_func.signature != SigRef::reserved_value() {
writeln!(w, " {} = {}", fnref, ext_func)?;
}
}
for (jt, jt_data) in &func.jump_tables {
any = true;
writeln!(w, " {} = {}", jt, jt_data)?;
}
Ok(any)
}
//---------------------------------------------------------------------- //----------------------------------------------------------------------
// //
// Basic blocks // Basic blocks