1747ad3c4Slazypassion //! The `CFGPrinter` utility. 2747ad3c4Slazypassion 310e226f9Sbjorn3 use alloc::vec::Vec; 4*bb8fa40eSbjorn3 use core::fmt::{Display, Formatter, Result, Write}; 5747ad3c4Slazypassion 66042ee6fSbjorn3 use crate::entity::SecondaryMap; 7747ad3c4Slazypassion use crate::flowgraph::{BasicBlock, 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. 20747ad3c4Slazypassion 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`. 28d7d48d5cSBenjamin Bouvier pub fn write(&self, w: &mut dyn Write) -> Result { 29747ad3c4Slazypassion self.header(w)?; 30747ad3c4Slazypassion self.ebb_nodes(w)?; 31747ad3c4Slazypassion self.cfg_connections(w)?; 32747ad3c4Slazypassion writeln!(w, "}}") 33747ad3c4Slazypassion } 34747ad3c4Slazypassion 35d7d48d5cSBenjamin 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() { 38747ad3c4Slazypassion writeln!(w, " {{rank=min; {}}}", entry)?; 39747ad3c4Slazypassion } 40747ad3c4Slazypassion Ok(()) 41747ad3c4Slazypassion } 42747ad3c4Slazypassion 43d7d48d5cSBenjamin Bouvier fn ebb_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 52747ad3c4Slazypassion for ebb in &self.func.layout { 536042ee6fSbjorn3 write!(w, " {} [shape=record, label=\"{{", ebb)?; 546042ee6fSbjorn3 crate::write::write_ebb_header(w, self.func, None, ebb, 4)?; 55747ad3c4Slazypassion // Add all outgoing branch instructions to the label. 56747ad3c4Slazypassion for inst in self.func.layout.ebb_insts(ebb) { 576042ee6fSbjorn3 write!(w, " | <{}>", inst)?; 586042ee6fSbjorn3 PlainWriter.write_instruction(w, self.func, &aliases, None, inst, 0)?; 59747ad3c4Slazypassion } 60747ad3c4Slazypassion writeln!(w, "}}\"]")? 61747ad3c4Slazypassion } 62747ad3c4Slazypassion Ok(()) 63747ad3c4Slazypassion } 64747ad3c4Slazypassion 65d7d48d5cSBenjamin Bouvier fn cfg_connections(&self, w: &mut dyn Write) -> Result { 66747ad3c4Slazypassion for ebb in &self.func.layout { 67747ad3c4Slazypassion for BasicBlock { ebb: parent, inst } in self.cfg.pred_iter(ebb) { 68747ad3c4Slazypassion writeln!(w, " {}:{} -> {}", parent, inst, ebb)?; 69747ad3c4Slazypassion } 70747ad3c4Slazypassion } 71747ad3c4Slazypassion Ok(()) 72747ad3c4Slazypassion } 73747ad3c4Slazypassion } 74747ad3c4Slazypassion 75747ad3c4Slazypassion impl<'a> Display for CFGPrinter<'a> { 76747ad3c4Slazypassion fn fmt(&self, f: &mut Formatter) -> Result { 77747ad3c4Slazypassion self.write(f) 78747ad3c4Slazypassion } 79747ad3c4Slazypassion } 80