Pretty printing preamble errors. (#472)
* Pretty printing preamble errors.
This commit is contained in:
committed by
Dan Gohman
parent
0a65089a36
commit
8e74a4f8fc
@@ -1,9 +1,9 @@
|
||||
//! Utility routines for pretty-printing error messages.
|
||||
|
||||
use ir;
|
||||
use ir::entities::Inst;
|
||||
use ir::entities::{AnyEntity, Inst};
|
||||
use ir::function::Function;
|
||||
use isa::{RegInfo, TargetIsa};
|
||||
use isa::TargetIsa;
|
||||
use result::CodegenError;
|
||||
use std::boxed::Box;
|
||||
use std::fmt;
|
||||
@@ -23,25 +23,6 @@ pub fn pretty_verifier_error<'a>(
|
||||
let mut errors = errors.0;
|
||||
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(
|
||||
&mut PrettyVerifierError(func_w.unwrap_or(Box::new(PlainWriter)), &mut errors),
|
||||
&mut w,
|
||||
@@ -62,21 +43,22 @@ impl<'a> FuncWriter for PrettyVerifierError<'a> {
|
||||
inst: Inst,
|
||||
indent: usize,
|
||||
) -> 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,
|
||||
w: &mut Write,
|
||||
func: &Function,
|
||||
regs: Option<&RegInfo>,
|
||||
) -> Result<bool, fmt::Error> {
|
||||
self.0.write_preamble(w, func, regs)
|
||||
entity: AnyEntity,
|
||||
value: &fmt::Display,
|
||||
) -> fmt::Result {
|
||||
pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
|
||||
}
|
||||
}
|
||||
|
||||
/// Pretty-print a function verifier error.
|
||||
fn pretty_function_error(
|
||||
fn pretty_instruction_error(
|
||||
w: &mut Write,
|
||||
func: &Function,
|
||||
isa: Option<&TargetIsa>,
|
||||
@@ -125,6 +107,48 @@ fn pretty_function_error(
|
||||
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.
|
||||
pub fn pretty_error(func: &ir::Function, isa: Option<&TargetIsa>, err: CodegenError) -> String {
|
||||
if let CodegenError::Verifier(e) = err {
|
||||
|
||||
@@ -3,15 +3,16 @@
|
||||
//! 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.
|
||||
|
||||
use ir::entities::AnyEntity;
|
||||
use ir::{DataFlowGraph, Ebb, Function, Inst, SigRef, Type, Value, ValueDef};
|
||||
use isa::{RegInfo, TargetIsa};
|
||||
use packed_option::ReservedValue;
|
||||
use std::fmt::{self, Write};
|
||||
use std::string::String;
|
||||
|
||||
/// A `FuncWriter` is used to decorate functions during printing
|
||||
/// A `FuncWriter` used to decorate functions during printing.
|
||||
pub trait FuncWriter {
|
||||
/// Write the given inst to w
|
||||
/// Write the given `inst` to `w`.
|
||||
fn write_instruction(
|
||||
&mut self,
|
||||
w: &mut Write,
|
||||
@@ -21,16 +22,66 @@ pub trait FuncWriter {
|
||||
ident: usize,
|
||||
) -> fmt::Result;
|
||||
|
||||
/// Write the preamble to w
|
||||
/// Write the preamble to `w`. By default, this uses `write_entity_definition`.
|
||||
fn write_preamble(
|
||||
&mut self,
|
||||
w: &mut Write,
|
||||
func: &Function,
|
||||
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;
|
||||
|
||||
impl FuncWriter for PlainWriter {
|
||||
@@ -44,15 +95,6 @@ impl FuncWriter for PlainWriter {
|
||||
) -> fmt::Result {
|
||||
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.
|
||||
@@ -61,7 +103,7 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) -
|
||||
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.
|
||||
/// pretty_function_error is passed as 'closure' to add error decoration.
|
||||
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))
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user