1747ad3c4Slazypassion //! Utility routines for pretty-printing error messages.
2747ad3c4Slazypassion 
3747ad3c4Slazypassion use crate::entity::SecondaryMap;
4747ad3c4Slazypassion use crate::ir;
5832666c4SRyan Hunt use crate::ir::entities::{AnyEntity, Block, Inst, Value};
6747ad3c4Slazypassion use crate::ir::function::Function;
7747ad3c4Slazypassion use crate::result::CodegenError;
8747ad3c4Slazypassion use crate::verifier::{VerifierError, VerifierErrors};
990ac295eSAlex Crichton use crate::write::{FuncWriter, PlainWriter, decorate_function};
1010e226f9Sbjorn3 use alloc::boxed::Box;
1110e226f9Sbjorn3 use alloc::string::{String, ToString};
1210e226f9Sbjorn3 use alloc::vec::Vec;
13bb8fa40eSbjorn3 use core::fmt;
14bb8fa40eSbjorn3 use core::fmt::Write;
15747ad3c4Slazypassion 
16747ad3c4Slazypassion /// Pretty-print a verifier error.
pretty_verifier_error<'a>( func: &ir::Function, func_w: Option<Box<dyn FuncWriter + 'a>>, errors: VerifierErrors, ) -> String17747ad3c4Slazypassion pub fn pretty_verifier_error<'a>(
18747ad3c4Slazypassion     func: &ir::Function,
19d7d48d5cSBenjamin Bouvier     func_w: Option<Box<dyn FuncWriter + 'a>>,
20747ad3c4Slazypassion     errors: VerifierErrors,
21747ad3c4Slazypassion ) -> String {
22747ad3c4Slazypassion     let mut errors = errors.0;
23747ad3c4Slazypassion     let mut w = String::new();
24747ad3c4Slazypassion     let num_errors = errors.len();
25747ad3c4Slazypassion 
26747ad3c4Slazypassion     decorate_function(
27747ad3c4Slazypassion         &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors),
28747ad3c4Slazypassion         &mut w,
29747ad3c4Slazypassion         func,
30747ad3c4Slazypassion     )
31747ad3c4Slazypassion     .unwrap();
32747ad3c4Slazypassion 
33747ad3c4Slazypassion     writeln!(
34747ad3c4Slazypassion         w,
35747ad3c4Slazypassion         "\n; {} verifier error{} detected (see above). Compilation aborted.",
36747ad3c4Slazypassion         num_errors,
37747ad3c4Slazypassion         if num_errors == 1 { "" } else { "s" }
38747ad3c4Slazypassion     )
39747ad3c4Slazypassion     .unwrap();
40747ad3c4Slazypassion 
41747ad3c4Slazypassion     w
42747ad3c4Slazypassion }
43747ad3c4Slazypassion 
44d7d48d5cSBenjamin Bouvier struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
45747ad3c4Slazypassion 
46747ad3c4Slazypassion impl<'a> FuncWriter for PrettyVerifierError<'a> {
write_block_header( &mut self, w: &mut dyn Write, func: &Function, block: Block, indent: usize, ) -> fmt::Result47832666c4SRyan Hunt     fn write_block_header(
48747ad3c4Slazypassion         &mut self,
49d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
50747ad3c4Slazypassion         func: &Function,
51832666c4SRyan Hunt         block: Block,
52747ad3c4Slazypassion         indent: usize,
53747ad3c4Slazypassion     ) -> fmt::Result {
5443a86f14SBenjamin Bouvier         pretty_block_header_error(w, func, block, indent, &mut *self.0, self.1)
55747ad3c4Slazypassion     }
56747ad3c4Slazypassion 
write_instruction( &mut self, w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, inst: Inst, indent: usize, ) -> fmt::Result57747ad3c4Slazypassion     fn write_instruction(
58747ad3c4Slazypassion         &mut self,
59d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
60747ad3c4Slazypassion         func: &Function,
61747ad3c4Slazypassion         aliases: &SecondaryMap<Value, Vec<Value>>,
62747ad3c4Slazypassion         inst: Inst,
63747ad3c4Slazypassion         indent: usize,
64747ad3c4Slazypassion     ) -> fmt::Result {
6543a86f14SBenjamin Bouvier         pretty_instruction_error(w, func, aliases, inst, indent, &mut *self.0, self.1)
66747ad3c4Slazypassion     }
67747ad3c4Slazypassion 
write_entity_definition( &mut self, w: &mut dyn Write, func: &Function, entity: AnyEntity, value: &dyn fmt::Display, ) -> fmt::Result68747ad3c4Slazypassion     fn write_entity_definition(
69747ad3c4Slazypassion         &mut self,
70d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
71747ad3c4Slazypassion         func: &Function,
72747ad3c4Slazypassion         entity: AnyEntity,
73d7d48d5cSBenjamin Bouvier         value: &dyn fmt::Display,
74747ad3c4Slazypassion     ) -> fmt::Result {
75*2f7dbd61SChris Fallin         pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
76747ad3c4Slazypassion     }
77747ad3c4Slazypassion }
78747ad3c4Slazypassion 
79832666c4SRyan Hunt /// Pretty-print a function verifier error for a given block.
pretty_block_header_error( w: &mut dyn Write, func: &Function, cur_block: Block, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result80832666c4SRyan Hunt fn pretty_block_header_error(
81d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
82747ad3c4Slazypassion     func: &Function,
83832666c4SRyan Hunt     cur_block: Block,
84747ad3c4Slazypassion     indent: usize,
85d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
86747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
87747ad3c4Slazypassion ) -> fmt::Result {
88747ad3c4Slazypassion     let mut s = String::new();
8943a86f14SBenjamin Bouvier     func_w.write_block_header(&mut s, func, cur_block, indent)?;
90a0442ea0SHamir Mahal     write!(w, "{s}")?;
91747ad3c4Slazypassion 
92747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
93747ad3c4Slazypassion     let mut i = 0;
94747ad3c4Slazypassion     let mut printed_error = false;
95747ad3c4Slazypassion     while i != errors.len() {
96747ad3c4Slazypassion         match errors[i].location {
97832666c4SRyan Hunt             ir::entities::AnyEntity::Block(block) if block == cur_block => {
98747ad3c4Slazypassion                 if !printed_error {
99747ad3c4Slazypassion                     print_arrow(w, &s)?;
100747ad3c4Slazypassion                     printed_error = true;
101747ad3c4Slazypassion                 }
102747ad3c4Slazypassion                 let err = errors.remove(i);
103747ad3c4Slazypassion                 print_error(w, err)?;
104747ad3c4Slazypassion             }
105747ad3c4Slazypassion             _ => i += 1,
106747ad3c4Slazypassion         }
107747ad3c4Slazypassion     }
108747ad3c4Slazypassion 
109747ad3c4Slazypassion     if printed_error {
110747ad3c4Slazypassion         w.write_char('\n')?;
111747ad3c4Slazypassion     }
112747ad3c4Slazypassion 
113747ad3c4Slazypassion     Ok(())
114747ad3c4Slazypassion }
115747ad3c4Slazypassion 
116747ad3c4Slazypassion /// Pretty-print a function verifier error for a given instruction.
pretty_instruction_error( w: &mut dyn Write, func: &Function, aliases: &SecondaryMap<Value, Vec<Value>>, cur_inst: Inst, indent: usize, func_w: &mut dyn FuncWriter, errors: &mut Vec<VerifierError>, ) -> fmt::Result117747ad3c4Slazypassion fn pretty_instruction_error(
118d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
119747ad3c4Slazypassion     func: &Function,
120747ad3c4Slazypassion     aliases: &SecondaryMap<Value, Vec<Value>>,
121747ad3c4Slazypassion     cur_inst: Inst,
122747ad3c4Slazypassion     indent: usize,
123d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
124747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
125747ad3c4Slazypassion ) -> fmt::Result {
126747ad3c4Slazypassion     let mut s = String::new();
12743a86f14SBenjamin Bouvier     func_w.write_instruction(&mut s, func, aliases, cur_inst, indent)?;
128a0442ea0SHamir Mahal     write!(w, "{s}")?;
129747ad3c4Slazypassion 
130747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
131747ad3c4Slazypassion     let mut i = 0;
132747ad3c4Slazypassion     let mut printed_error = false;
133747ad3c4Slazypassion     while i != errors.len() {
134747ad3c4Slazypassion         match errors[i].location {
135747ad3c4Slazypassion             ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
136747ad3c4Slazypassion                 if !printed_error {
137747ad3c4Slazypassion                     print_arrow(w, &s)?;
138747ad3c4Slazypassion                     printed_error = true;
139747ad3c4Slazypassion                 }
140747ad3c4Slazypassion                 let err = errors.remove(i);
141747ad3c4Slazypassion                 print_error(w, err)?;
142747ad3c4Slazypassion             }
143747ad3c4Slazypassion             _ => i += 1,
144747ad3c4Slazypassion         }
145747ad3c4Slazypassion     }
146747ad3c4Slazypassion 
147747ad3c4Slazypassion     if printed_error {
148747ad3c4Slazypassion         w.write_char('\n')?;
149747ad3c4Slazypassion     }
150747ad3c4Slazypassion 
151747ad3c4Slazypassion     Ok(())
152747ad3c4Slazypassion }
153747ad3c4Slazypassion 
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::Result154747ad3c4Slazypassion fn pretty_preamble_error(
155d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
156747ad3c4Slazypassion     func: &Function,
157747ad3c4Slazypassion     entity: AnyEntity,
158d7d48d5cSBenjamin Bouvier     value: &dyn fmt::Display,
159d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
160747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
161747ad3c4Slazypassion ) -> fmt::Result {
162747ad3c4Slazypassion     let mut s = String::new();
163*2f7dbd61SChris Fallin     func_w.write_entity_definition(&mut s, func, entity, value)?;
164a0442ea0SHamir Mahal     write!(w, "{s}")?;
165747ad3c4Slazypassion 
166747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
167747ad3c4Slazypassion     let mut i = 0;
168747ad3c4Slazypassion     let mut printed_error = false;
169747ad3c4Slazypassion     while i != errors.len() {
170747ad3c4Slazypassion         if entity == errors[i].location {
171747ad3c4Slazypassion             if !printed_error {
172747ad3c4Slazypassion                 print_arrow(w, &s)?;
173747ad3c4Slazypassion                 printed_error = true;
174747ad3c4Slazypassion             }
175747ad3c4Slazypassion             let err = errors.remove(i);
176747ad3c4Slazypassion             print_error(w, err)?;
177747ad3c4Slazypassion         } else {
178747ad3c4Slazypassion             i += 1
179747ad3c4Slazypassion         }
180747ad3c4Slazypassion     }
181747ad3c4Slazypassion 
182747ad3c4Slazypassion     if printed_error {
183747ad3c4Slazypassion         w.write_char('\n')?;
184747ad3c4Slazypassion     }
185747ad3c4Slazypassion 
186747ad3c4Slazypassion     Ok(())
187747ad3c4Slazypassion }
188747ad3c4Slazypassion 
189747ad3c4Slazypassion /// Prints:
190747ad3c4Slazypassion ///    ;   ^~~~~~
print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result191d7d48d5cSBenjamin Bouvier fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result {
192747ad3c4Slazypassion     write!(w, ";")?;
193747ad3c4Slazypassion 
194747ad3c4Slazypassion     let indent = entity.len() - entity.trim_start().len();
195747ad3c4Slazypassion     if indent != 0 {
196747ad3c4Slazypassion         write!(w, "{1:0$}^", indent - 1, "")?;
197747ad3c4Slazypassion     }
198747ad3c4Slazypassion 
199747ad3c4Slazypassion     for _ in 0..entity.trim().len() - 1 {
200747ad3c4Slazypassion         write!(w, "~")?;
201747ad3c4Slazypassion     }
202747ad3c4Slazypassion 
203747ad3c4Slazypassion     writeln!(w)
204747ad3c4Slazypassion }
205747ad3c4Slazypassion 
206747ad3c4Slazypassion /// Prints:
207747ad3c4Slazypassion ///    ; error: [ERROR BODY]
print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result208d7d48d5cSBenjamin Bouvier fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
209747ad3c4Slazypassion     writeln!(w, "; error: {}", err.to_string())?;
210747ad3c4Slazypassion     Ok(())
211747ad3c4Slazypassion }
212747ad3c4Slazypassion 
213747ad3c4Slazypassion /// Pretty-print a Cranelift error.
pretty_error(func: &ir::Function, err: CodegenError) -> String21443a86f14SBenjamin Bouvier pub fn pretty_error(func: &ir::Function, err: CodegenError) -> String {
215747ad3c4Slazypassion     if let CodegenError::Verifier(e) = err {
21643a86f14SBenjamin Bouvier         pretty_verifier_error(func, None, e)
217747ad3c4Slazypassion     } else {
218747ad3c4Slazypassion         err.to_string()
219747ad3c4Slazypassion     }
220747ad3c4Slazypassion }
221