1 //! The `CFGPrinter` utility. 2 3 use core::fmt::{Display, Formatter, Result, Write}; 4 use std::vec::Vec; 5 6 use crate::entity::SecondaryMap; 7 use crate::flowgraph::{BasicBlock, ControlFlowGraph}; 8 use crate::ir::Function; 9 use crate::write::{FuncWriter, PlainWriter}; 10 11 /// A utility for pretty-printing the CFG of a `Function`. 12 pub struct CFGPrinter<'a> { 13 func: &'a Function, 14 cfg: ControlFlowGraph, 15 } 16 17 /// A utility for pretty-printing the CFG of a `Function`. 18 impl<'a> CFGPrinter<'a> { 19 /// Create a new CFGPrinter. new(func: &'a Function) -> Self20 pub fn new(func: &'a Function) -> Self { 21 Self { 22 func, 23 cfg: ControlFlowGraph::with_function(func), 24 } 25 } 26 27 /// Write the CFG for this function to `w`. write(&self, w: &mut dyn Write) -> Result28 pub fn write(&self, w: &mut dyn Write) -> Result { 29 self.header(w)?; 30 self.ebb_nodes(w)?; 31 self.cfg_connections(w)?; 32 writeln!(w, "}}") 33 } 34 header(&self, w: &mut dyn Write) -> Result35 fn header(&self, w: &mut dyn Write) -> Result { 36 writeln!(w, "digraph \"{}\" {{", self.func.name)?; 37 if let Some(entry) = self.func.layout.entry_block() { 38 writeln!(w, " {{rank=min; {}}}", entry)?; 39 } 40 Ok(()) 41 } 42 ebb_nodes(&self, w: &mut dyn Write) -> Result43 fn ebb_nodes(&self, w: &mut dyn Write) -> Result { 44 let mut aliases = SecondaryMap::<_, Vec<_>>::new(); 45 for v in self.func.dfg.values() { 46 // VADFS returns the immediate target of an alias 47 if let Some(k) = self.func.dfg.value_alias_dest_for_serialization(v) { 48 aliases[k].push(v); 49 } 50 } 51 52 for ebb in &self.func.layout { 53 write!(w, " {} [shape=record, label=\"{{", ebb)?; 54 crate::write::write_ebb_header(w, self.func, None, ebb, 4)?; 55 // Add all outgoing branch instructions to the label. 56 for inst in self.func.layout.ebb_insts(ebb) { 57 write!(w, " | <{}>", inst)?; 58 PlainWriter.write_instruction(w, self.func, &aliases, None, inst, 0)?; 59 } 60 writeln!(w, "}}\"]")? 61 } 62 Ok(()) 63 } 64 cfg_connections(&self, w: &mut dyn Write) -> Result65 fn cfg_connections(&self, w: &mut dyn 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> { fmt(&self, f: &mut Formatter) -> Result76 fn fmt(&self, f: &mut Formatter) -> Result { 77 self.write(f) 78 } 79 } 80