cranelift_codegen/
cfg_printer.rs1use alloc::vec::Vec;
4use core::fmt::{Display, Formatter, Result, Write};
5
6use crate::entity::SecondaryMap;
7use crate::flowgraph::{BlockPredecessor, ControlFlowGraph};
8use crate::ir::Function;
9use crate::write::{FuncWriter, PlainWriter};
10
11pub struct CFGPrinter<'a> {
13 func: &'a Function,
14 cfg: ControlFlowGraph,
15}
16
17impl<'a> CFGPrinter<'a> {
19 pub fn new(func: &'a Function) -> Self {
21 Self {
22 func,
23 cfg: ControlFlowGraph::with_function(func),
24 }
25 }
26
27 pub fn write(&self, w: &mut dyn Write) -> Result {
29 self.header(w)?;
30 self.block_nodes(w)?;
31 self.cfg_connections(w)?;
32 writeln!(w, "}}")
33 }
34
35 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
43 fn block_nodes(&self, w: &mut dyn Write) -> Result {
44 let mut aliases = SecondaryMap::<_, Vec<_>>::new();
45 for v in self.func.dfg.values() {
46 if let Some(k) = self.func.dfg.value_alias_dest_for_serialization(v) {
48 aliases[k].push(v);
49 }
50 }
51
52 for block in &self.func.layout {
53 write!(w, " {block} [shape=record, label=\"{{")?;
54 crate::write::write_block_header(w, self.func, block, 4)?;
55 if let Some(inst) = self.func.layout.last_inst(block) {
57 write!(w, " | <{inst}>")?;
58 PlainWriter.write_instruction(w, self.func, &aliases, inst, 0)?;
59 }
60 writeln!(w, "}}\"]")?
61 }
62 Ok(())
63 }
64
65 fn cfg_connections(&self, w: &mut dyn Write) -> Result {
66 for block in &self.func.layout {
67 for BlockPredecessor {
68 block: parent,
69 inst,
70 } in self.cfg.pred_iter(block)
71 {
72 writeln!(w, " {parent}:{inst} -> {block}")?;
73 }
74 }
75 Ok(())
76 }
77}
78
79impl<'a> Display for CFGPrinter<'a> {
80 fn fmt(&self, f: &mut Formatter) -> Result {
81 self.write(f)
82 }
83}