1 //! Utility routines for pretty-printing error messages.
2
3 use crate::entity::SecondaryMap;
4 use crate::ir;
5 use crate::ir::entities::{AnyEntity, Block, 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.
pretty_verifier_error<'a>( func: &ir::Function, isa: Option<&dyn TargetIsa>, func_w: Option<Box<dyn FuncWriter + 'a>>, errors: VerifierErrors, ) -> String18 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> {
write_block_header( &mut self, w: &mut dyn Write, func: &Function, isa: Option<&dyn TargetIsa>, block: Block, indent: usize, ) -> fmt::Result50 fn write_block_header(
51 &mut self,
52 w: &mut dyn Write,
53 func: &Function,
54 isa: Option<&dyn TargetIsa>,
55 block: Block,
56 indent: usize,
57 ) -> fmt::Result {
58 pretty_block_header_error(w, func, isa, block, indent, &mut *self.0, self.1)
59 }
60
write_instruction( &mut self, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, isa: Option<&dyn TargetIsa>, inst: Inst, indent: usize, ) -> fmt::Result61 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
write_entity_definition( &mut self, w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, ) -> fmt::Result73 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 block.
pretty_block_header_error( w: &mut dyn Write, func: &Function, isa: Option<&dyn TargetIsa>, cur_block: Block, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result85 fn pretty_block_header_error(
86 w: &mut dyn Write,
87 func: &Function,
88 isa: Option<&dyn TargetIsa>,
89 cur_block: Block,
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_block_header(&mut s, func, isa, cur_block, 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::Block(block) if block == cur_block => {
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.
pretty_instruction_error( w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, isa: Option<&dyn TargetIsa>, cur_inst: Inst, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result123 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
pretty_preamble_error( w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result161 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 /// ; ^~~~~~
print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result198 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]
print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result215 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.
pretty_error(func: &ir::Function, isa: Option<&dyn TargetIsa>, err: CodegenError) -> String221 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