1 //! The `CFGPrinter` utility.
2 
3 use core::fmt::{Display, Formatter, Result, Write};
4 
5 use crate::flowgraph::{BasicBlock, ControlFlowGraph};
6 use crate::ir::instructions::BranchInfo;
7 use crate::ir::Function;
8 
9 /// A utility for pretty-printing the CFG of a `Function`.
10 pub struct CFGPrinter<'a> {
11     func: &'a Function,
12     cfg: ControlFlowGraph,
13 }
14 
15 /// A utility for pretty-printing the CFG of a `Function`.
16 impl<'a> CFGPrinter<'a> {
17     /// Create a new CFGPrinter.
18     pub fn new(func: &'a Function) -> Self {
19         Self {
20             func,
21             cfg: ControlFlowGraph::with_function(func),
22         }
23     }
24 
25     /// Write the CFG for this function to `w`.
26     pub fn write(&self, w: &mut Write) -> Result {
27         self.header(w)?;
28         self.ebb_nodes(w)?;
29         self.cfg_connections(w)?;
30         writeln!(w, "}}")
31     }
32 
33     fn header(&self, w: &mut Write) -> Result {
34         writeln!(w, "digraph \"{}\" {{", self.func.name)?;
35         if let Some(entry) = self.func.layout.entry_block() {
36             writeln!(w, "    {{rank=min; {}}}", entry)?;
37         }
38         Ok(())
39     }
40 
41     fn ebb_nodes(&self, w: &mut Write) -> Result {
42         for ebb in &self.func.layout {
43             write!(w, "    {} [shape=record, label=\"{{{}", ebb, ebb)?;
44             // Add all outgoing branch instructions to the label.
45             for inst in self.func.layout.ebb_insts(ebb) {
46                 let idata = &self.func.dfg[inst];
47                 match idata.analyze_branch(&self.func.dfg.value_lists) {
48                     BranchInfo::SingleDest(dest, _) => {
49                         write!(w, " | <{}>{} {}", inst, idata.opcode(), dest)?
50                     }
51                     BranchInfo::Table(table, dest) => {
52                         write!(w, " | <{}>{} {}", inst, idata.opcode(), table)?;
53                         if let Some(dest) = dest {
54                             write!(w, " {}", dest)?
55                         }
56                     }
57                     BranchInfo::NotABranch => {}
58                 }
59             }
60             writeln!(w, "}}\"]")?
61         }
62         Ok(())
63     }
64 
65     fn cfg_connections(&self, w: &mut Write) -> Result {
66         for ebb in &self.func.layout {
67             for BasicBlock { ebb: parent, inst } in self.cfg.pred_iter(ebb) {
68                 writeln!(w, "    {}:{} -> {}", parent, inst, ebb)?;
69             }
70         }
71         Ok(())
72     }
73 }
74 
75 impl<'a> Display for CFGPrinter<'a> {
76     fn fmt(&self, f: &mut Formatter) -> Result {
77         self.write(f)
78     }
79 }
80