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