1747ad3c4Slazypassion //! Utility routines for pretty-printing error messages.
2747ad3c4Slazypassion 
3747ad3c4Slazypassion use crate::entity::SecondaryMap;
4747ad3c4Slazypassion use crate::ir;
5747ad3c4Slazypassion use crate::ir::entities::{AnyEntity, Ebb, Inst, Value};
6747ad3c4Slazypassion use crate::ir::function::Function;
7747ad3c4Slazypassion use crate::isa::TargetIsa;
8747ad3c4Slazypassion use crate::result::CodegenError;
9747ad3c4Slazypassion use crate::verifier::{VerifierError, VerifierErrors};
10747ad3c4Slazypassion use crate::write::{decorate_function, FuncWriter, PlainWriter};
1110e226f9Sbjorn3 use alloc::boxed::Box;
1210e226f9Sbjorn3 use alloc::string::{String, ToString};
1310e226f9Sbjorn3 use alloc::vec::Vec;
14*bb8fa40eSbjorn3 use core::fmt;
15*bb8fa40eSbjorn3 use core::fmt::Write;
16747ad3c4Slazypassion 
17747ad3c4Slazypassion /// Pretty-print a verifier error.
18747ad3c4Slazypassion pub fn pretty_verifier_error<'a>(
19747ad3c4Slazypassion     func: &ir::Function,
20d7d48d5cSBenjamin Bouvier     isa: Option<&dyn TargetIsa>,
21d7d48d5cSBenjamin Bouvier     func_w: Option<Box<dyn FuncWriter + 'a>>,
22747ad3c4Slazypassion     errors: VerifierErrors,
23747ad3c4Slazypassion ) -> String {
24747ad3c4Slazypassion     let mut errors = errors.0;
25747ad3c4Slazypassion     let mut w = String::new();
26747ad3c4Slazypassion     let num_errors = errors.len();
27747ad3c4Slazypassion 
28747ad3c4Slazypassion     decorate_function(
29747ad3c4Slazypassion         &mut PrettyVerifierError(func_w.unwrap_or_else(|| Box::new(PlainWriter)), &mut errors),
30747ad3c4Slazypassion         &mut w,
31747ad3c4Slazypassion         func,
328f95c517SYury Delendik         &isa.into(),
33747ad3c4Slazypassion     )
34747ad3c4Slazypassion     .unwrap();
35747ad3c4Slazypassion 
36747ad3c4Slazypassion     writeln!(
37747ad3c4Slazypassion         w,
38747ad3c4Slazypassion         "\n; {} verifier error{} detected (see above). Compilation aborted.",
39747ad3c4Slazypassion         num_errors,
40747ad3c4Slazypassion         if num_errors == 1 { "" } else { "s" }
41747ad3c4Slazypassion     )
42747ad3c4Slazypassion     .unwrap();
43747ad3c4Slazypassion 
44747ad3c4Slazypassion     w
45747ad3c4Slazypassion }
46747ad3c4Slazypassion 
47d7d48d5cSBenjamin Bouvier struct PrettyVerifierError<'a>(Box<dyn FuncWriter + 'a>, &'a mut Vec<VerifierError>);
48747ad3c4Slazypassion 
49747ad3c4Slazypassion impl<'a> FuncWriter for PrettyVerifierError<'a> {
50747ad3c4Slazypassion     fn write_ebb_header(
51747ad3c4Slazypassion         &mut self,
52d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
53747ad3c4Slazypassion         func: &Function,
54d7d48d5cSBenjamin Bouvier         isa: Option<&dyn TargetIsa>,
55747ad3c4Slazypassion         ebb: Ebb,
56747ad3c4Slazypassion         indent: usize,
57747ad3c4Slazypassion     ) -> fmt::Result {
58747ad3c4Slazypassion         pretty_ebb_header_error(w, func, isa, ebb, indent, &mut *self.0, self.1)
59747ad3c4Slazypassion     }
60747ad3c4Slazypassion 
61747ad3c4Slazypassion     fn write_instruction(
62747ad3c4Slazypassion         &mut self,
63d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
64747ad3c4Slazypassion         func: &Function,
65747ad3c4Slazypassion         aliases: &SecondaryMap<Value, Vec<Value>>,
66d7d48d5cSBenjamin Bouvier         isa: Option<&dyn TargetIsa>,
67747ad3c4Slazypassion         inst: Inst,
68747ad3c4Slazypassion         indent: usize,
69747ad3c4Slazypassion     ) -> fmt::Result {
70747ad3c4Slazypassion         pretty_instruction_error(w, func, aliases, isa, inst, indent, &mut *self.0, self.1)
71747ad3c4Slazypassion     }
72747ad3c4Slazypassion 
73747ad3c4Slazypassion     fn write_entity_definition(
74747ad3c4Slazypassion         &mut self,
75d7d48d5cSBenjamin Bouvier         w: &mut dyn Write,
76747ad3c4Slazypassion         func: &Function,
77747ad3c4Slazypassion         entity: AnyEntity,
78d7d48d5cSBenjamin Bouvier         value: &dyn fmt::Display,
79747ad3c4Slazypassion     ) -> fmt::Result {
80747ad3c4Slazypassion         pretty_preamble_error(w, func, entity, value, &mut *self.0, self.1)
81747ad3c4Slazypassion     }
82747ad3c4Slazypassion }
83747ad3c4Slazypassion 
84747ad3c4Slazypassion /// Pretty-print a function verifier error for a given EBB.
85747ad3c4Slazypassion fn pretty_ebb_header_error(
86d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
87747ad3c4Slazypassion     func: &Function,
88d7d48d5cSBenjamin Bouvier     isa: Option<&dyn TargetIsa>,
89747ad3c4Slazypassion     cur_ebb: Ebb,
90747ad3c4Slazypassion     indent: usize,
91d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
92747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
93747ad3c4Slazypassion ) -> fmt::Result {
94747ad3c4Slazypassion     let mut s = String::new();
95747ad3c4Slazypassion     func_w.write_ebb_header(&mut s, func, isa, cur_ebb, indent)?;
96747ad3c4Slazypassion     write!(w, "{}", s)?;
97747ad3c4Slazypassion 
98747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
99747ad3c4Slazypassion     let mut i = 0;
100747ad3c4Slazypassion     let mut printed_error = false;
101747ad3c4Slazypassion     while i != errors.len() {
102747ad3c4Slazypassion         match errors[i].location {
103747ad3c4Slazypassion             ir::entities::AnyEntity::Ebb(ebb) if ebb == cur_ebb => {
104747ad3c4Slazypassion                 if !printed_error {
105747ad3c4Slazypassion                     print_arrow(w, &s)?;
106747ad3c4Slazypassion                     printed_error = true;
107747ad3c4Slazypassion                 }
108747ad3c4Slazypassion                 let err = errors.remove(i);
109747ad3c4Slazypassion                 print_error(w, err)?;
110747ad3c4Slazypassion             }
111747ad3c4Slazypassion             _ => i += 1,
112747ad3c4Slazypassion         }
113747ad3c4Slazypassion     }
114747ad3c4Slazypassion 
115747ad3c4Slazypassion     if printed_error {
116747ad3c4Slazypassion         w.write_char('\n')?;
117747ad3c4Slazypassion     }
118747ad3c4Slazypassion 
119747ad3c4Slazypassion     Ok(())
120747ad3c4Slazypassion }
121747ad3c4Slazypassion 
122747ad3c4Slazypassion /// Pretty-print a function verifier error for a given instruction.
123747ad3c4Slazypassion fn pretty_instruction_error(
124d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
125747ad3c4Slazypassion     func: &Function,
126747ad3c4Slazypassion     aliases: &SecondaryMap<Value, Vec<Value>>,
127d7d48d5cSBenjamin Bouvier     isa: Option<&dyn TargetIsa>,
128747ad3c4Slazypassion     cur_inst: Inst,
129747ad3c4Slazypassion     indent: usize,
130d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
131747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
132747ad3c4Slazypassion ) -> fmt::Result {
133747ad3c4Slazypassion     let mut s = String::new();
134747ad3c4Slazypassion     func_w.write_instruction(&mut s, func, aliases, isa, cur_inst, indent)?;
135747ad3c4Slazypassion     write!(w, "{}", s)?;
136747ad3c4Slazypassion 
137747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
138747ad3c4Slazypassion     let mut i = 0;
139747ad3c4Slazypassion     let mut printed_error = false;
140747ad3c4Slazypassion     while i != errors.len() {
141747ad3c4Slazypassion         match errors[i].location {
142747ad3c4Slazypassion             ir::entities::AnyEntity::Inst(inst) if inst == cur_inst => {
143747ad3c4Slazypassion                 if !printed_error {
144747ad3c4Slazypassion                     print_arrow(w, &s)?;
145747ad3c4Slazypassion                     printed_error = true;
146747ad3c4Slazypassion                 }
147747ad3c4Slazypassion                 let err = errors.remove(i);
148747ad3c4Slazypassion                 print_error(w, err)?;
149747ad3c4Slazypassion             }
150747ad3c4Slazypassion             _ => i += 1,
151747ad3c4Slazypassion         }
152747ad3c4Slazypassion     }
153747ad3c4Slazypassion 
154747ad3c4Slazypassion     if printed_error {
155747ad3c4Slazypassion         w.write_char('\n')?;
156747ad3c4Slazypassion     }
157747ad3c4Slazypassion 
158747ad3c4Slazypassion     Ok(())
159747ad3c4Slazypassion }
160747ad3c4Slazypassion 
161747ad3c4Slazypassion fn pretty_preamble_error(
162d7d48d5cSBenjamin Bouvier     w: &mut dyn Write,
163747ad3c4Slazypassion     func: &Function,
164747ad3c4Slazypassion     entity: AnyEntity,
165d7d48d5cSBenjamin Bouvier     value: &dyn fmt::Display,
166d7d48d5cSBenjamin Bouvier     func_w: &mut dyn FuncWriter,
167747ad3c4Slazypassion     errors: &mut Vec<VerifierError>,
168747ad3c4Slazypassion ) -> fmt::Result {
169747ad3c4Slazypassion     let mut s = String::new();
170747ad3c4Slazypassion     func_w.write_entity_definition(&mut s, func, entity, value)?;
171747ad3c4Slazypassion     write!(w, "{}", s)?;
172747ad3c4Slazypassion 
173747ad3c4Slazypassion     // TODO: Use drain_filter here when it gets stabilized
174747ad3c4Slazypassion     let mut i = 0;
175747ad3c4Slazypassion     let mut printed_error = false;
176747ad3c4Slazypassion     while i != errors.len() {
177747ad3c4Slazypassion         if entity == errors[i].location {
178747ad3c4Slazypassion             if !printed_error {
179747ad3c4Slazypassion                 print_arrow(w, &s)?;
180747ad3c4Slazypassion                 printed_error = true;
181747ad3c4Slazypassion             }
182747ad3c4Slazypassion             let err = errors.remove(i);
183747ad3c4Slazypassion             print_error(w, err)?;
184747ad3c4Slazypassion         } else {
185747ad3c4Slazypassion             i += 1
186747ad3c4Slazypassion         }
187747ad3c4Slazypassion     }
188747ad3c4Slazypassion 
189747ad3c4Slazypassion     if printed_error {
190747ad3c4Slazypassion         w.write_char('\n')?;
191747ad3c4Slazypassion     }
192747ad3c4Slazypassion 
193747ad3c4Slazypassion     Ok(())
194747ad3c4Slazypassion }
195747ad3c4Slazypassion 
196747ad3c4Slazypassion /// Prints:
197747ad3c4Slazypassion ///    ;   ^~~~~~
198d7d48d5cSBenjamin Bouvier fn print_arrow(w: &mut dyn Write, entity: &str) -> fmt::Result {
199747ad3c4Slazypassion     write!(w, ";")?;
200747ad3c4Slazypassion 
201747ad3c4Slazypassion     let indent = entity.len() - entity.trim_start().len();
202747ad3c4Slazypassion     if indent != 0 {
203747ad3c4Slazypassion         write!(w, "{1:0$}^", indent - 1, "")?;
204747ad3c4Slazypassion     }
205747ad3c4Slazypassion 
206747ad3c4Slazypassion     for _ in 0..entity.trim().len() - 1 {
207747ad3c4Slazypassion         write!(w, "~")?;
208747ad3c4Slazypassion     }
209747ad3c4Slazypassion 
210747ad3c4Slazypassion     writeln!(w)
211747ad3c4Slazypassion }
212747ad3c4Slazypassion 
213747ad3c4Slazypassion /// Prints:
214747ad3c4Slazypassion ///    ; error: [ERROR BODY]
215d7d48d5cSBenjamin Bouvier fn print_error(w: &mut dyn Write, err: VerifierError) -> fmt::Result {
216747ad3c4Slazypassion     writeln!(w, "; error: {}", err.to_string())?;
217747ad3c4Slazypassion     Ok(())
218747ad3c4Slazypassion }
219747ad3c4Slazypassion 
220747ad3c4Slazypassion /// Pretty-print a Cranelift error.
221d7d48d5cSBenjamin Bouvier pub fn pretty_error(func: &ir::Function, isa: Option<&dyn TargetIsa>, err: CodegenError) -> String {
222747ad3c4Slazypassion     if let CodegenError::Verifier(e) = err {
223747ad3c4Slazypassion         pretty_verifier_error(func, isa, None, e)
224747ad3c4Slazypassion     } else {
225747ad3c4Slazypassion         err.to_string()
226747ad3c4Slazypassion     }
227747ad3c4Slazypassion }
228