1 //! Utility routines for pretty-printing error messages. 2 3 use crate::entity::SecondaryMap; 4 use crate::ir; 5 use crate::ir::entities::{AnyEntity, Ebb, Inst, Value}; 6 use crate::ir::function::Function; 7 use crate::isa::TargetIsa; 8 use crate::result::CodegenError; 9 use crate::verifier::{VerifierError, VerifierErrors}; 10 use crate::write::{decorate_function, FuncWriter, PlainWriter}; 11 use alloc::boxed::Box; 12 use alloc::string::{String, ToString}; 13 use alloc::vec::Vec; 14 use core::fmt; 15 use core::fmt::Write; 16 17 /// Pretty-print a verifier error. 18 pub fn pretty_verifier_error<'a>( 19 func: &ir::Function, 20 isa: Option<&dyn TargetIsa>, 21 func_w: Option<Box<dyn FuncWriter + 'a>>, 22 errors: VerifierErrors, 23 ) -> String { 24 let mut errors = errors.0; 25 let mut w = String::new(); 26 let num_errors = errors.len(); 27 28 decorate_function( 29 &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors), 30 &mut w, 31 func, 32 &isa.into(), 33 ) 34 .unwrap(); 35 36 writeln!( 37 w, 38 "\n; {} verifier error{} detected (see above). Compilation aborted.", 39 num_errors, 40 if num_errors == 1 { "" } else { "s" } 41 ) 42 .unwrap(); 43 44 w 45 } 46 47 struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>); 48 49 impl<'a> FuncWriter for PrettyVerifierError<'a> { 50 fn write_ebb_header( 51 &mut self, 52 w: &mut dyn Write, 53 func: &Function, 54 isa: Option<&dyn TargetIsa>, 55 ebb: Ebb, 56 indent: usize, 57 ) -> fmt::Result { 58 pretty_ebb_header_error(w, func, isa, ebb, indent, &mut *self.0, self.1) 59 } 60 61 fn write_instruction( 62 &mut self, 63 w: &mut dyn Write, 64 func: &Function, 65 aliases: &SecondaryMap<Value, Vec<Value>>, 66 isa: Option<&dyn TargetIsa>, 67 inst: Inst, 68 indent: usize, 69 ) -> fmt::Result { 70 pretty_instruction_error(w, func, aliases, isa, inst, indent, &mut *self.0, self.1) 71 } 72 73 fn write_entity_definition( 74 &mut self, 75 w: &mut dyn Write, 76 func: &Function, 77 entity: AnyEntity, 78 value: &dyn fmt::Display, 79 ) -> fmt::Result { 80 pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1) 81 } 82 } 83 84 /// Pretty-print a function verifier error for a given EBB. 85 fn pretty_ebb_header_error( 86 w: &mut dyn Write, 87 func: &Function, 88 isa: Option<&dyn TargetIsa>, 89 cur_ebb: Ebb, 90 indent: usize, 91 func_w: &mut dyn FuncWriter, 92 errors: &mut Vec<VerifierError>, 93 ) -> fmt::Result { 94 let mut s = String::new(); 95 func_w.write_ebb_header(&mut s, func, isa, cur_ebb, indent)?; 96 write!(w, "{}", s)?; 97 98 // TODO: Use drain_filter here when it gets stabilized 99 let mut i = 0; 100 let mut printed_error = false; 101 while i != errors.len() { 102 match errors[i].location { 103 ir::entities::AnyEntity::Ebb(ebb) if ebb == cur_ebb => { 104 if !printed_error { 105 print_arrow(w, &s)?; 106 printed_error = true; 107 } 108 let err = errors.remove(i); 109 print_error(w, err)?; 110 } 111 _ => i += 1, 112 } 113 } 114 115 if printed_error { 116 w.write_char('\n')?; 117 } 118 119 Ok(()) 120 } 121 122 /// Pretty-print a function verifier error for a given instruction. 123 fn pretty_instruction_error( 124 w: &mut dyn Write, 125 func: &Function, 126 aliases: &SecondaryMap<Value, Vec<Value>>, 127 isa: Option<&dyn TargetIsa>, 128 cur_inst: Inst, 129 indent: usize, 130 func_w: &mut dyn FuncWriter, 131 errors: &mut Vec<VerifierError>, 132 ) -> fmt::Result { 133 let mut s = String::new(); 134 func_w.write_instruction(&mut s, func, aliases, isa, cur_inst, indent)?; 135 write!(w, "{}", s)?; 136 137 // TODO: Use drain_filter here when it gets stabilized 138 let mut i = 0; 139 let mut printed_error = false; 140 while i != errors.len() { 141 match errors[i].location { 142 ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => { 143 if !printed_error { 144 print_arrow(w, &s)?; 145 printed_error = true; 146 } 147 let err = errors.remove(i); 148 print_error(w, err)?; 149 } 150 _ => i += 1, 151 } 152 } 153 154 if printed_error { 155 w.write_char('\n')?; 156 } 157 158 Ok(()) 159 } 160 161 fn pretty_preamble_error( 162 w: &mut dyn Write, 163 func: &Function, 164 entity: AnyEntity, 165 value: &dyn fmt::Display, 166 func_w: &mut dyn FuncWriter, 167 errors: &mut Vec<VerifierError>, 168 ) -> fmt::Result { 169 let mut s = String::new(); 170 func_w.write_entity_definition(&mut s, func, entity, value)?; 171 write!(w, "{}", s)?; 172 173 // TODO: Use drain_filter here when it gets stabilized 174 let mut i = 0; 175 let mut printed_error = false; 176 while i != errors.len() { 177 if entity == errors[i].location { 178 if !printed_error { 179 print_arrow(w, &s)?; 180 printed_error = true; 181 } 182 let err = errors.remove(i); 183 print_error(w, err)?; 184 } else { 185 i += 1 186 } 187 } 188 189 if printed_error { 190 w.write_char('\n')?; 191 } 192 193 Ok(()) 194 } 195 196 /// Prints: 197 /// ; ^~~~~~ 198 fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result { 199 write!(w, ";")?; 200 201 let indent = entity.len() - entity.trim_start().len(); 202 if indent != 0 { 203 write!(w, "{1:0$}^", indent - 1, "")?; 204 } 205 206 for _ in 0..entity.trim().len() - 1 { 207 write!(w, "~")?; 208 } 209 210 writeln!(w) 211 } 212 213 /// Prints: 214 /// ; error: [ERROR BODY] 215 fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result { 216 writeln!(w, "; error: {}", err.to_string())?; 217 Ok(()) 218 } 219 220 /// Pretty-print a Cranelift error. 221 pub fn pretty_error(func: &ir::Function, isa: Option<&dyn TargetIsa>, err: CodegenError) -> String { 222 if let CodegenError::Verifier(e) = err { 223 pretty_verifier_error(func, isa, None, e) 224 } else { 225 err.to_string() 226 } 227 } 228