1 /* Output routines for graphical representation.
2 Copyright (C) 1998-2024 Free Software Foundation, Inc.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4 Rewritten for DOT output by Steven Bosscher, 2012.
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
24 #include "coretypes.h"
27 #include "pretty-print.h"
28 #include "diagnostic-core.h" /* for fatal_error */
34 /* DOT files with the .dot extension are recognized as document templates
35 by a well-known piece of word processing software out of Redmond, WA.
36 Therefore some recommend using the .gv extension instead. Obstinately
37 ignore that recommendation... */
38 static const char *const graph_ext
= ".dot";
40 /* Open a file with MODE for dumping our graph to.
41 Return the file pointer. */
43 open_graph_file (const char *base
, const char *mode
)
45 size_t namelen
= strlen (base
);
46 size_t extlen
= strlen (graph_ext
) + 1;
47 char *buf
= XALLOCAVEC (char, namelen
+ extlen
);
50 memcpy (buf
, base
, namelen
);
51 memcpy (buf
+ namelen
, graph_ext
, extlen
);
53 fp
= fopen (buf
, mode
);
55 fatal_error (input_location
, "cannot open %s: %m", buf
);
60 /* Disable warnings about quoting issues in the pp_xxx calls below
61 that (intentionally) don't follow GCC diagnostic conventions. */
63 # pragma GCC diagnostic push
64 # pragma GCC diagnostic ignored "-Wformat-diag"
67 /* Draw a basic block BB belonging to the function with FUNCDEF_NO
68 as its unique number. */
70 draw_cfg_node (pretty_printer
*pp
, int funcdef_no
, basic_block bb
)
73 const char *fillcolor
;
75 if (bb
->index
== ENTRY_BLOCK
|| bb
->index
== EXIT_BLOCK
)
84 BB_PARTITION (bb
) == BB_HOT_PARTITION
? "lightpink"
85 : BB_PARTITION (bb
) == BB_COLD_PARTITION
? "lightblue"
90 "\tfn_%d_basic_block_%d "
91 "[shape=%s,style=filled,fillcolor=%s,label=\"",
92 funcdef_no
, bb
->index
, shape
, fillcolor
);
94 if (bb
->index
== ENTRY_BLOCK
)
95 pp_string (pp
, "ENTRY");
96 else if (bb
->index
== EXIT_BLOCK
)
97 pp_string (pp
, "EXIT");
101 pp_write_text_to_stream (pp
);
102 dump_bb_for_graph (pp
, bb
);
106 pp_string (pp
, "\"];\n\n");
110 /* Draw all successor edges of a basic block BB belonging to the function
111 with FUNCDEF_NO as its unique number. */
113 draw_cfg_node_succ_edges (pretty_printer
*pp
, int funcdef_no
, basic_block bb
)
117 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
119 const char *style
= "\"solid,bold\"";
120 const char *color
= "black";
123 if (e
->flags
& EDGE_FAKE
)
129 else if (e
->flags
& EDGE_DFS_BACK
)
131 style
= "\"dotted,bold\"";
135 else if (e
->flags
& EDGE_FALLTHRU
)
137 else if (e
->flags
& EDGE_TRUE_VALUE
)
138 color
= "forestgreen";
139 else if (e
->flags
& EDGE_FALSE_VALUE
)
140 color
= "darkorange";
142 if (e
->flags
& EDGE_ABNORMAL
)
146 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
147 "[style=%s,color=%s,weight=%d,constraint=%s",
148 funcdef_no
, e
->src
->index
,
149 funcdef_no
, e
->dest
->index
,
150 style
, color
, weight
,
151 (e
->flags
& (EDGE_FAKE
| EDGE_DFS_BACK
)) ? "false" : "true");
152 if (e
->probability
.initialized_p ())
153 pp_printf (pp
, ",label=\"[%i%%]\"",
154 e
->probability
.to_reg_br_prob_base ()
155 * 100 / REG_BR_PROB_BASE
);
156 pp_printf (pp
, "];\n");
161 /* Draw all the basic blocks in the CFG in case loops are not available.
162 First compute a topological order of the blocks to get a good ranking of
163 the nodes. Then, if any nodes are not reachable from ENTRY, add them at
167 draw_cfg_nodes_no_loops (pretty_printer
*pp
, struct function
*fun
)
169 int *rpo
= XNEWVEC (int, n_basic_blocks_for_fn (fun
));
172 auto_sbitmap
visited (last_basic_block_for_fn (fun
));
173 bitmap_clear (visited
);
175 n
= pre_and_rev_post_order_compute_fn (fun
, NULL
, rpo
, true);
176 for (i
= n_basic_blocks_for_fn (fun
) - n
;
177 i
< n_basic_blocks_for_fn (fun
); i
++)
179 basic_block bb
= BASIC_BLOCK_FOR_FN (fun
, rpo
[i
]);
180 draw_cfg_node (pp
, fun
->funcdef_no
, bb
);
181 bitmap_set_bit (visited
, bb
->index
);
185 if (n
!= n_basic_blocks_for_fn (fun
))
187 /* Some blocks are unreachable. We still want to dump them. */
189 FOR_ALL_BB_FN (bb
, fun
)
190 if (! bitmap_bit_p (visited
, bb
->index
))
191 draw_cfg_node (pp
, fun
->funcdef_no
, bb
);
195 /* Draw all the basic blocks in LOOP. Print the blocks in breath-first
196 order to get a good ranking of the nodes. This function is recursive:
197 It first prints inner loops, then the body of LOOP itself. */
200 draw_cfg_nodes_for_loop (pretty_printer
*pp
, int funcdef_no
,
205 const char *fillcolors
[3] = { "grey88", "grey77", "grey66" };
207 if (loop
->header
!= NULL
208 && loop
->latch
!= EXIT_BLOCK_PTR_FOR_FN (cfun
))
210 "\tsubgraph cluster_%d_%d {\n"
211 "\tstyle=\"filled\";\n"
212 "\tcolor=\"darkgreen\";\n"
213 "\tfillcolor=\"%s\";\n"
214 "\tlabel=\"loop %d\";\n"
217 funcdef_no
, loop
->num
,
218 fillcolors
[(loop_depth (loop
) - 1) % 3],
221 for (class loop
*inner
= loop
->inner
; inner
; inner
= inner
->next
)
222 draw_cfg_nodes_for_loop (pp
, funcdef_no
, inner
);
224 if (loop
->header
== NULL
)
227 if (loop
->latch
== EXIT_BLOCK_PTR_FOR_FN (cfun
))
228 body
= get_loop_body (loop
);
230 body
= get_loop_body_in_bfs_order (loop
);
232 for (i
= 0; i
< loop
->num_nodes
; i
++)
234 basic_block bb
= body
[i
];
235 if (bb
->loop_father
== loop
)
236 draw_cfg_node (pp
, funcdef_no
, bb
);
241 if (loop
->latch
!= EXIT_BLOCK_PTR_FOR_FN (cfun
))
242 pp_printf (pp
, "\t}\n");
245 /* Draw all the basic blocks in the CFG in case the loop tree is available.
246 All loop bodys are printed in clusters. */
249 draw_cfg_nodes (pretty_printer
*pp
, struct function
*fun
)
251 /* ??? The loop and dominance APIs are dependent on fun == cfun. */
252 if (fun
== cfun
&& loops_for_fn (fun
))
253 draw_cfg_nodes_for_loop (pp
, fun
->funcdef_no
, get_loop (fun
, 0));
255 draw_cfg_nodes_no_loops (pp
, fun
);
258 /* Draw all edges in the CFG. Retreating edges are drawin as not
259 constraining, this makes the layout of the graph better. */
262 draw_cfg_edges (pretty_printer
*pp
, struct function
*fun
)
266 /* Save EDGE_DFS_BACK flag to dfs_back. */
267 auto_bitmap dfs_back
;
270 unsigned int idx
= 0;
271 FOR_EACH_BB_FN (bb
, fun
)
272 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
274 if (e
->flags
& EDGE_DFS_BACK
)
275 bitmap_set_bit (dfs_back
, idx
);
279 mark_dfs_back_edges (fun
);
280 FOR_ALL_BB_FN (bb
, fun
)
281 draw_cfg_node_succ_edges (pp
, fun
->funcdef_no
, bb
);
283 /* Restore EDGE_DFS_BACK flag from dfs_back. */
285 FOR_EACH_BB_FN (bb
, fun
)
286 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
288 if (bitmap_bit_p (dfs_back
, idx
))
289 e
->flags
|= EDGE_DFS_BACK
;
291 e
->flags
&= ~EDGE_DFS_BACK
;
295 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
297 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
298 "[style=\"invis\",constraint=true];\n",
299 fun
->funcdef_no
, ENTRY_BLOCK
,
300 fun
->funcdef_no
, EXIT_BLOCK
);
304 /* Print a graphical representation of the CFG of function FUN.
305 First print all basic blocks. Draw all edges at the end to get
306 subgraphs right for GraphViz, which requires nodes to be defined
307 before edges to cluster nodes properly. */
310 print_graph_cfg (FILE *fp
, struct function
*fun
)
312 pretty_printer graph_slim_pp
;
313 graph_slim_pp
.buffer
->stream
= fp
;
314 pretty_printer
*const pp
= &graph_slim_pp
;
315 const char *funcname
= function_name (fun
);
316 pp_printf (pp
, "subgraph \"cluster_%s\" {\n"
317 "\tstyle=\"dashed\";\n"
318 "\tcolor=\"black\";\n"
319 "\tlabel=\"%s ()\";\n",
321 draw_cfg_nodes (pp
, fun
);
322 draw_cfg_edges (pp
, fun
);
323 pp_printf (pp
, "}\n");
327 /* Overload with additional flag argument. */
330 print_graph_cfg (FILE *fp
, struct function
*fun
, dump_flags_t flags
)
332 dump_flags_t saved_dump_flags
= dump_flags
;
334 print_graph_cfg (fp
, fun
);
335 dump_flags
= saved_dump_flags
;
339 /* Print a graphical representation of the CFG of function FUN.
340 First print all basic blocks. Draw all edges at the end to get
341 subgraphs right for GraphViz, which requires nodes to be defined
342 before edges to cluster nodes properly. */
345 print_graph_cfg (const char *base
, struct function
*fun
)
347 FILE *fp
= open_graph_file (base
, "a");
348 print_graph_cfg (fp
, fun
);
352 /* Start the dump of a graph. */
354 start_graph_dump (FILE *fp
, const char *base
)
356 pretty_printer graph_slim_pp
;
357 graph_slim_pp
.buffer
->stream
= fp
;
358 pretty_printer
*const pp
= &graph_slim_pp
;
359 pp_string (pp
, "digraph \"");
360 pp_write_text_to_stream (pp
);
361 pp_string (pp
, base
);
362 pp_write_text_as_dot_label_to_stream (pp
, /*for_record=*/false);
363 pp_string (pp
, "\" {\n");
364 pp_string (pp
, "overlap=false;\n");
368 /* End the dump of a graph. */
370 end_graph_dump (FILE *fp
)
375 /* Similar as clean_dump_file, but this time for graph output files. */
377 clean_graph_dump_file (const char *base
)
379 FILE *fp
= open_graph_file (base
, "w");
380 start_graph_dump (fp
, base
);
385 /* Do final work on the graph output file. */
387 finish_graph_dump_file (const char *base
)
389 FILE *fp
= open_graph_file (base
, "a");
395 # pragma GCC diagnostic pop