diff --git a/lib/codegen/src/print_errors.rs b/lib/codegen/src/print_errors.rs index 472f8ab005..6e14182b1d 100644 --- a/lib/codegen/src/print_errors.rs +++ b/lib/codegen/src/print_errors.rs @@ -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 { - 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, +) -> 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 { diff --git a/lib/codegen/src/write.rs b/lib/codegen/src/write.rs index d4d98b9ced..2d2fcf5621 100644 --- a/lib/codegen/src/write.rs +++ b/lib/codegen/src/write.rs @@ -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; + ) -> Result { + 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 { - 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( @@ -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 { - 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