diff --git a/lib/codegen/src/print_errors.rs b/lib/codegen/src/print_errors.rs index 777fde05b8..61e10d7ed1 100644 --- a/lib/codegen/src/print_errors.rs +++ b/lib/codegen/src/print_errors.rs @@ -1,11 +1,15 @@ //! Utility routines for pretty-printing error messages. use ir; +use ir::entities::Inst; +use ir::function::Function; use isa::TargetIsa; use result::CodegenError; +use std::fmt; use std::fmt::Write; use std::string::{String, ToString}; use verifier::VerifierError; +use write::decorate_function; /// Pretty-print a verifier error. pub fn pretty_verifier_error( @@ -13,15 +17,52 @@ pub fn pretty_verifier_error( isa: Option<&TargetIsa>, err: &VerifierError, ) -> String { - let mut msg = err.to_string(); + let mut w = String::new(); + decorate_function( + &mut |w, func, isa, inst, indent| pretty_function_error(w, func, isa, inst, indent, err), + &mut w, + func, + isa, + ).unwrap(); + w +} + +/// Pretty-print a function verifier error. +fn pretty_function_error( + w: &mut Write, + func: &Function, + isa: Option<&TargetIsa>, + cur_inst: Inst, + indent: usize, + err: &VerifierError, +) -> fmt::Result { match err.location { ir::entities::AnyEntity::Inst(inst) => { - write!(msg, "\n{}: {}\n\n", inst, func.dfg.display_inst(inst, isa)).unwrap() + if inst == cur_inst { + write!( + w, + "{1:0$}{2}\n", + indent, + "", + func.dfg.display_inst(cur_inst, isa) + )?; + write!(w, "{1:0$}{2}", indent, "", "^")?; + for _c in cur_inst.to_string().chars() { + write!(w, "~")?; + } + write!(w, "\n\nverifier {}\n\n", err.to_string()) + } else { + write!( + w, + "{1:0$}{2}\n", + indent, + "", + func.dfg.display_inst(cur_inst, isa) + ) + } } - _ => msg.push('\n'), + _ => write!(w, "{}", "\n"), } - write!(msg, "{}", func.display(isa)).unwrap(); - msg } /// Pretty-print a Cretonne error. diff --git a/lib/codegen/src/write.rs b/lib/codegen/src/write.rs index 124034b39a..9914c45517 100644 --- a/lib/codegen/src/write.rs +++ b/lib/codegen/src/write.rs @@ -9,9 +9,39 @@ use packed_option::ReservedValue; use std::fmt::{self, Write}; use std::string::String; +fn write_function_plain( + w: &mut Write, + func: &Function, + isa: Option<&TargetIsa>, + inst: Inst, + indent: usize, +) -> fmt::Result { + write_instruction(w, func, isa, inst, indent)?; + Ok(()) +} + /// Write `func` to `w` as equivalent text. /// Use `isa` to emit ISA-dependent annotations. pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) -> fmt::Result { + decorate_function( + &mut |w, func, isa, inst, indent| write_function_plain(w, func, isa, inst, indent), + w, + func, + isa, + ) +} + +/// 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< + WL: FnMut(&mut Write, &Function, Option<&TargetIsa>, Inst, usize) -> fmt::Result, +>( + closure: &mut WL, + w: &mut Write, + func: &Function, + isa: Option<&TargetIsa>, +) -> fmt::Result { let regs = isa.map(TargetIsa::register_info); let regs = regs.as_ref(); @@ -23,7 +53,7 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) - if any { writeln!(w)?; } - write_ebb(w, func, isa, ebb)?; + decorate_ebb(closure, w, func, isa, ebb)?; any = true; } writeln!(w, "}}") @@ -141,7 +171,15 @@ pub fn write_ebb_header( writeln!(w, "):") } -pub fn write_ebb(w: &mut Write, func: &Function, isa: Option<&TargetIsa>, ebb: Ebb) -> fmt::Result { +pub fn decorate_ebb< + WL: FnMut(&mut Write, &Function, Option<&TargetIsa>, Inst, usize) -> fmt::Result, +>( + closure: &mut WL, + w: &mut Write, + func: &Function, + isa: Option<&TargetIsa>, + ebb: Ebb, +) -> fmt::Result { // Indent all instructions if any encodings are present. let indent = if func.encodings.is_empty() && func.srclocs.is_empty() { 4 @@ -151,8 +189,9 @@ pub fn write_ebb(w: &mut Write, func: &Function, isa: Option<&TargetIsa>, ebb: E write_ebb_header(w, func, isa, ebb, indent)?; for inst in func.layout.ebb_insts(ebb) { - write_instruction(w, func, isa, inst, indent)?; + closure(w, func, isa, inst, indent)?; } + Ok(()) }