1747ad3c4Slazypassion //! The `CFGPrinter` utility. 2747ad3c4Slazypassion 310e226f9Sbjorn3 use alloc::vec::Vec; 4bb8fa40eSbjorn3 use core::fmt::{Display, Formatter, Result, Write}; 5747ad3c4Slazypassion 66042ee6fSbjorn3 use crate::entity::SecondaryMap; 7832666c4SRyan Hunt use crate::flowgraph::{BlockPredecessor, ControlFlowGraph}; 8747ad3c4Slazypassion use crate::ir::Function; 96042ee6fSbjorn3 use crate::write::{FuncWriter, PlainWriter}; 10747ad3c4Slazypassion 11747ad3c4Slazypassion /// A utility for pretty-printing the CFG of a `Function`. 12747ad3c4Slazypassion pub struct CFGPrinter<'a> { 13747ad3c4Slazypassion func: &'a Function, 14747ad3c4Slazypassion cfg: ControlFlowGraph, 15747ad3c4Slazypassion } 16747ad3c4Slazypassion 17747ad3c4Slazypassion /// A utility for pretty-printing the CFG of a `Function`. 18747ad3c4Slazypassion impl<'a> CFGPrinter<'a> { 19747ad3c4Slazypassion /// Create a new CFGPrinter. new(func: &'a Function) -> Self20747ad3c4Slazypassion pub fn new(func: &'a Function) -> Self { 21747ad3c4Slazypassion Self { 22747ad3c4Slazypassion func, 23747ad3c4Slazypassion cfg: ControlFlowGraph::with_function(func), 24747ad3c4Slazypassion } 25747ad3c4Slazypassion } 26747ad3c4Slazypassion 27747ad3c4Slazypassion /// Write the CFG for this function to `w`. write(&self, w: &mut dyn Write) -> Result28d7d48d5cSBenjamin Bouvier pub fn write(&self, w: &mut dyn Write) -> Result { 29747ad3c4Slazypassion self.header(w)?; 30832666c4SRyan Hunt self.block_nodes(w)?; 31747ad3c4Slazypassion self.cfg_connections(w)?; 32747ad3c4Slazypassion writeln!(w, "}}") 33747ad3c4Slazypassion } 34747ad3c4Slazypassion header(&self, w: &mut dyn Write) -> Result35d7d48d5cSBenjamin Bouvier fn header(&self, w: &mut dyn Write) -> Result { 36747ad3c4Slazypassion writeln!(w, "digraph \"{}\" {{", self.func.name)?; 37747ad3c4Slazypassion if let Some(entry) = self.func.layout.entry_block() { 38*a0442ea0SHamir Mahal writeln!(w, " {{rank=min; {entry}}}")?; 39747ad3c4Slazypassion } 40747ad3c4Slazypassion Ok(()) 41747ad3c4Slazypassion } 42747ad3c4Slazypassion block_nodes(&self, w: &mut dyn Write) -> Result43832666c4SRyan Hunt fn block_nodes(&self, w: &mut dyn Write) -> Result { 446042ee6fSbjorn3 let mut aliases = SecondaryMap::<_, Vec<_>>::new(); 456042ee6fSbjorn3 for v in self.func.dfg.values() { 466042ee6fSbjorn3 // VADFS returns the immediate target of an alias 476042ee6fSbjorn3 if let Some(k) = self.func.dfg.value_alias_dest_for_serialization(v) { 486042ee6fSbjorn3 aliases[k].push(v); 496042ee6fSbjorn3 } 506042ee6fSbjorn3 } 516042ee6fSbjorn3 52832666c4SRyan Hunt for block in &self.func.layout { 53*a0442ea0SHamir Mahal write!(w, " {block} [shape=record, label=\"{{")?; 5443a86f14SBenjamin Bouvier crate::write::write_block_header(w, self.func, block, 4)?; 55747ad3c4Slazypassion // Add all outgoing branch instructions to the label. 56a5698cedSTrevor Elliott if let Some(inst) = self.func.layout.last_inst(block) { 57*a0442ea0SHamir Mahal write!(w, " | <{inst}>")?; 5843a86f14SBenjamin Bouvier PlainWriter.write_instruction(w, self.func, &aliases, inst, 0)?; 59747ad3c4Slazypassion } 60747ad3c4Slazypassion writeln!(w, "}}\"]")? 61747ad3c4Slazypassion } 62747ad3c4Slazypassion Ok(()) 63747ad3c4Slazypassion } 64747ad3c4Slazypassion cfg_connections(&self, w: &mut dyn Write) -> Result65d7d48d5cSBenjamin Bouvier fn cfg_connections(&self, w: &mut dyn Write) -> Result { 66832666c4SRyan Hunt for block in &self.func.layout { 67832666c4SRyan Hunt for BlockPredecessor { 68832666c4SRyan Hunt block: parent, 69832666c4SRyan Hunt inst, 70832666c4SRyan Hunt } in self.cfg.pred_iter(block) 71832666c4SRyan Hunt { 72*a0442ea0SHamir Mahal writeln!(w, " {parent}:{inst} -> {block}")?; 73747ad3c4Slazypassion } 74747ad3c4Slazypassion } 75747ad3c4Slazypassion Ok(()) 76747ad3c4Slazypassion } 77747ad3c4Slazypassion } 78747ad3c4Slazypassion 79747ad3c4Slazypassion impl<'a> Display for CFGPrinter<'a> { fmt(&self, f: &mut Formatter) -> Result80747ad3c4Slazypassion fn fmt(&self, f: &mut Formatter) -> Result { 81747ad3c4Slazypassion self.write(f) 82747ad3c4Slazypassion } 83747ad3c4Slazypassion } 84