waffle/ir/
display.rs

1//! Displaying IR.
2
3use super::{FuncDecl, FunctionBody, Module, SourceLoc, ValueDef};
4use crate::entity::EntityRef;
5use std::collections::HashMap;
6use std::fmt::{Display, Formatter, Result as FmtResult};
7
8/// A wrapper around a `FunctionBody` together with some auxiliary
9/// information to perform a pretty-print of that function.
10pub struct FunctionBodyDisplay<'a> {
11    pub(crate) body: &'a FunctionBody,
12    pub(crate) indent: &'a str,
13    pub(crate) verbose: bool,
14    pub(crate) module: Option<&'a Module<'a>>,
15}
16
17impl<'a> Display for FunctionBodyDisplay<'a> {
18    fn fmt(&self, f: &mut Formatter) -> FmtResult {
19        let arg_tys = self
20            .body
21            .locals
22            .values()
23            .take(self.body.n_params)
24            .map(|&ty| format!("{}", ty))
25            .collect::<Vec<_>>();
26        let ret_tys = self
27            .body
28            .rets
29            .iter()
30            .map(|&ty| format!("{}", ty))
31            .collect::<Vec<_>>();
32        writeln!(
33            f,
34            "{}function({}) -> {} {{",
35            self.indent,
36            arg_tys.join(", "),
37            ret_tys.join(", ")
38        )?;
39
40        for (value, value_def) in self.body.values.entries() {
41            match value_def {
42                ValueDef::Operator(op, args, tys) if self.verbose => writeln!(
43                    f,
44                    "{}    {} = {} {} # {}",
45                    self.indent,
46                    value,
47                    op,
48                    self.body.arg_pool[*args]
49                        .iter()
50                        .map(|arg| format!("{}", arg))
51                        .collect::<Vec<_>>()
52                        .join(", "),
53                    self.body.type_pool[*tys]
54                        .iter()
55                        .map(|arg| format!("{}", arg))
56                        .collect::<Vec<_>>()
57                        .join(", ")
58                )?,
59                ValueDef::BlockParam(block, idx, ty) if self.verbose => writeln!(
60                    f,
61                    "{}    {} = blockparam {}, {} # {}",
62                    self.indent, value, block, idx, ty
63                )?,
64                ValueDef::Alias(alias_target) => {
65                    if self.verbose {
66                        writeln!(f, "{}    {} = {}", self.indent, value, alias_target)?
67                    }
68                }
69                ValueDef::PickOutput(val, idx, ty) => {
70                    writeln!(f, "{}    {} = {}.{} # {}", self.indent, value, val, idx, ty)?
71                }
72                ValueDef::Placeholder(ty) => {
73                    writeln!(f, "{}    {} = placeholder # {}", self.indent, value, ty)?
74                }
75                ValueDef::None => writeln!(f, "{}    {} = none", self.indent, value)?,
76                _ => {}
77            }
78        }
79
80        for (block_id, block) in self.body.blocks.entries() {
81            let block_params = block
82                .params
83                .iter()
84                .map(|(ty, val)| format!("{}: {}", val, ty))
85                .collect::<Vec<_>>();
86            writeln!(
87                f,
88                "{}  {}({}): # {}",
89                self.indent,
90                block_id,
91                block_params.join(", "),
92                block.desc
93            )?;
94            writeln!(
95                f,
96                "{}    # preds: {}",
97                self.indent,
98                block
99                    .preds
100                    .iter()
101                    .map(|pred| format!("{} ({})", pred, self.body.blocks[*pred].desc))
102                    .collect::<Vec<_>>()
103                    .join(", ")
104            )?;
105            writeln!(
106                f,
107                "{}    # succs: {}",
108                self.indent,
109                block
110                    .succs
111                    .iter()
112                    .map(|succ| format!("{} ({})", succ, self.body.blocks[*succ].desc))
113                    .collect::<Vec<_>>()
114                    .join(", ")
115            )?;
116            for (_, param) in &block.params {
117                if let Some(local) = self.body.value_locals[*param] {
118                    writeln!(f, "{}    # {}: {}", self.indent, param, local)?;
119                }
120            }
121            for &inst in &block.insts {
122                if let Some(local) = self.body.value_locals[inst] {
123                    writeln!(f, "{}    # {}: {}", self.indent, inst, local)?;
124                }
125                match &self.body.values[inst] {
126                    ValueDef::Operator(op, args, tys) => {
127                        let args = self.body.arg_pool[*args]
128                            .iter()
129                            .map(|&v| format!("{}", v))
130                            .collect::<Vec<_>>();
131                        let tys = self.body.type_pool[*tys]
132                            .iter()
133                            .map(|&ty| format!("{}", ty))
134                            .collect::<Vec<_>>();
135                        let loc = if self.body.source_locs[inst] != SourceLoc::invalid()
136                            && self.module.is_some()
137                        {
138                            let module = self.module.as_ref().unwrap();
139                            let loc = self.body.source_locs[inst];
140                            let data = &module.debug.source_locs[loc];
141                            let filename = &module.debug.source_files[data.file];
142                            format!("@{} {}:{}:{}", loc, filename, data.line, data.col)
143                        } else {
144                            "".to_owned()
145                        };
146                        writeln!(
147                            f,
148                            "{}    {} = {} {} # {} {}",
149                            self.indent,
150                            inst,
151                            op,
152                            args.join(", "),
153                            tys.join(", "),
154                            loc,
155                        )?;
156                    }
157                    ValueDef::PickOutput(val, idx, ty) => {
158                        writeln!(f, "{}    {} = {}.{} # {}", self.indent, inst, val, idx, ty)?;
159                    }
160                    ValueDef::Alias(val) => {
161                        writeln!(f, "{}    {} = {}", self.indent, inst, val)?;
162                    }
163                    _ => unreachable!(),
164                }
165            }
166            writeln!(f, "{}    {}", self.indent, block.terminator)?;
167        }
168
169        writeln!(f, "{}}}", self.indent)?;
170
171        Ok(())
172    }
173}
174
175pub struct ModuleDisplay<'a> {
176    pub(crate) module: &'a Module<'a>,
177}
178
179impl<'a> Display for ModuleDisplay<'a> {
180    fn fmt(&self, f: &mut Formatter) -> FmtResult {
181        writeln!(f, "module {{")?;
182        if let Some(func) = self.module.start_func {
183            writeln!(f, "    start = {}", func)?;
184        }
185        let mut sig_strs = HashMap::new();
186        for (sig, sig_data) in self.module.signatures.entries() {
187            let arg_tys = sig_data
188                .params
189                .iter()
190                .map(|&ty| format!("{}", ty))
191                .collect::<Vec<_>>();
192            let ret_tys = sig_data
193                .returns
194                .iter()
195                .map(|&ty| format!("{}", ty))
196                .collect::<Vec<_>>();
197            let sig_str = format!("{} -> {}", arg_tys.join(", "), ret_tys.join(", "));
198            sig_strs.insert(sig, sig_str.clone());
199            writeln!(f, "  {}: {}", sig, sig_str)?;
200        }
201        for (global, global_data) in self.module.globals.entries() {
202            writeln!(
203                f,
204                "  {}: {:?} # {}",
205                global, global_data.value, global_data.ty
206            )?;
207        }
208        for (table, table_data) in self.module.tables.entries() {
209            writeln!(f, "  {}: {}", table, table_data.ty)?;
210            if let Some(funcs) = &table_data.func_elements {
211                for (i, &func) in funcs.iter().enumerate() {
212                    writeln!(f, "    {}[{}]: {}", table, i, func)?;
213                }
214            }
215        }
216        for (memory, memory_data) in self.module.memories.entries() {
217            writeln!(
218                f,
219                "  {}: initial {} max {:?}",
220                memory, memory_data.initial_pages, memory_data.maximum_pages
221            )?;
222            for seg in &memory_data.segments {
223                writeln!(
224                    f,
225                    "    {} offset {}: # {} bytes",
226                    memory,
227                    seg.offset,
228                    seg.data.len()
229                )?;
230            }
231        }
232        for import in &self.module.imports {
233            writeln!(
234                f,
235                "  import \"{}\".\"{}\": {}",
236                import.module, import.name, import.kind
237            )?;
238        }
239        for export in &self.module.exports {
240            writeln!(f, "  export \"{}\": {}", export.name, export.kind)?;
241        }
242        for (func, func_decl) in self.module.funcs.entries() {
243            match func_decl {
244                FuncDecl::Body(sig, name, body) => {
245                    writeln!(
246                        f,
247                        "  {} \"{}\": {} = # {}",
248                        func,
249                        name,
250                        sig,
251                        sig_strs.get(&sig).unwrap()
252                    )?;
253                    writeln!(f, "{}", body.display("    ", Some(self.module)))?;
254                }
255                FuncDecl::Lazy(sig, name, reader) => {
256                    writeln!(
257                        f,
258                        "  {} \"{}\": {} = # {}",
259                        func,
260                        name,
261                        sig,
262                        sig_strs.get(&sig).unwrap()
263                    )?;
264                    writeln!(f, "  # raw bytes (length {})", reader.range().len())?;
265                }
266                FuncDecl::Compiled(sig, name, _) => {
267                    writeln!(
268                        f,
269                        "  {} \"{}\": {} = # {}",
270                        func,
271                        name,
272                        sig,
273                        sig_strs.get(&sig).unwrap()
274                    )?;
275                    writeln!(f, "  # already compiled")?;
276                }
277                FuncDecl::Import(sig, name) => {
278                    writeln!(
279                        f,
280                        "  {} \"{}\": {} # {}",
281                        func,
282                        name,
283                        sig,
284                        sig_strs.get(&sig).unwrap()
285                    )?;
286                }
287                FuncDecl::None => {
288                    writeln!(f, "  {}: none", func)?;
289                }
290            }
291        }
292        for (loc, loc_data) in self.module.debug.source_locs.entries() {
293            writeln!(
294                f,
295                "  {} = {} line {} column {}",
296                loc, loc_data.file, loc_data.line, loc_data.col
297            )?;
298        }
299        for (file, file_name) in self.module.debug.source_files.entries() {
300            writeln!(f, "  {} = \"{}\"", file, file_name)?;
301        }
302        writeln!(f, "}}")?;
303        Ok(())
304    }
305}