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