]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/graph.c
Update copyright years.
[thirdparty/gcc.git] / gcc / graph.c
CommitLineData
735a0e33 1/* Output routines for graphical representation.
8d9254fc 2 Copyright (C) 1998-2020 Free Software Foundation, Inc.
735a0e33 3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
a27a5de9 4 Rewritten for DOT output by Steven Bosscher, 2012.
735a0e33 5
1322177d 6This file is part of GCC.
735a0e33 7
1322177d
LB
8GCC is free software; you can redistribute it and/or modify it under
9the terms of the GNU General Public License as published by the Free
9dcd6f09 10Software Foundation; either version 3, or (at your option) any later
1322177d 11version.
735a0e33 12
1322177d
LB
13GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16for more details.
735a0e33 17
400500c4 18You should have received a copy of the GNU General Public License
9dcd6f09
NC
19along with GCC; see the file COPYING3. If not see
20<http://www.gnu.org/licenses/>. */
735a0e33 21
71f3e391 22#include "config.h"
735a0e33 23#include "system.h"
4977bab6 24#include "coretypes.h"
c7131fb2 25#include "backend.h"
957060b5
AM
26#include "cfghooks.h"
27#include "pretty-print.h"
28#include "diagnostic-core.h" /* for fatal_error */
60393bbc 29#include "cfganal.h"
13475df1 30#include "cfgloop.h"
6a2cc2ac 31#include "graph.h"
bddb7adb 32#include "dumpfile.h"
735a0e33 33
a27a5de9
SB
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
13475df1 37 ignore that recommendation... */
a27a5de9 38static const char *const graph_ext = ".dot";
208d8b55 39
a27a5de9
SB
40/* Open a file with MODE for dumping our graph to.
41 Return the file pointer. */
42static FILE *
43open_graph_file (const char *base, const char *mode)
735a0e33 44{
a27a5de9
SB
45 size_t namelen = strlen (base);
46 size_t extlen = strlen (graph_ext) + 1;
47 char *buf = XALLOCAVEC (char, namelen + extlen);
48 FILE *fp;
735a0e33 49
a27a5de9
SB
50 memcpy (buf, base, namelen);
51 memcpy (buf + namelen, graph_ext, extlen);
735a0e33 52
a27a5de9
SB
53 fp = fopen (buf, mode);
54 if (fp == NULL)
0ecf545c 55 fatal_error (input_location, "cannot open %s: %m", buf);
735a0e33 56
a27a5de9 57 return fp;
735a0e33
UD
58}
59
0ecf545c
MS
60/* Disable warnings about quoting issues in the pp_xxx calls below
61 that (intentionally) don't follow GCC diagnostic conventions. */
62#if __GNUC__ >= 10
63# pragma GCC diagnostic push
64# pragma GCC diagnostic ignored "-Wformat-diag"
65#endif
66
2c895bd1 67/* Draw a basic block BB belonging to the function with FUNCDEF_NO
a27a5de9
SB
68 as its unique number. */
69static void
2c895bd1 70draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
a27a5de9 71{
a27a5de9
SB
72 const char *shape;
73 const char *fillcolor;
735a0e33 74
a27a5de9 75 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
735a0e33 76 {
a27a5de9
SB
77 shape = "Mdiamond";
78 fillcolor = "white";
735a0e33 79 }
735a0e33 80 else
735a0e33 81 {
a27a5de9
SB
82 shape = "record";
83 fillcolor =
84 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
85 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
86 : "lightgrey";
735a0e33 87 }
735a0e33 88
7eba871a
SB
89 pp_printf (pp,
90 "\tfn_%d_basic_block_%d "
91 "[shape=%s,style=filled,fillcolor=%s,label=\"",
2c895bd1 92 funcdef_no, bb->index, shape, fillcolor);
735a0e33 93
a27a5de9 94 if (bb->index == ENTRY_BLOCK)
7eba871a 95 pp_string (pp, "ENTRY");
a27a5de9 96 else if (bb->index == EXIT_BLOCK)
7eba871a 97 pp_string (pp, "EXIT");
a27a5de9 98 else
735a0e33 99 {
07838b13 100 pp_left_brace (pp);
7eba871a 101 pp_write_text_to_stream (pp);
2c895bd1 102 dump_bb_for_graph (pp, bb);
07838b13 103 pp_right_brace (pp);
735a0e33 104 }
a27a5de9 105
7eba871a
SB
106 pp_string (pp, "\"];\n\n");
107 pp_flush (pp);
735a0e33
UD
108}
109
a27a5de9 110/* Draw all successor edges of a basic block BB belonging to the function
2c895bd1 111 with FUNCDEF_NO as its unique number. */
735a0e33 112static void
2c895bd1 113draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
735a0e33 114{
a27a5de9
SB
115 edge e;
116 edge_iterator ei;
117 FOR_EACH_EDGE (e, ei, bb->succs)
735a0e33 118 {
a27a5de9
SB
119 const char *style = "\"solid,bold\"";
120 const char *color = "black";
121 int weight = 10;
735a0e33 122
a27a5de9 123 if (e->flags & EDGE_FAKE)
735a0e33 124 {
a27a5de9
SB
125 style = "dotted";
126 color = "green";
127 weight = 0;
735a0e33 128 }
a27a5de9 129 else if (e->flags & EDGE_DFS_BACK)
735a0e33 130 {
a27a5de9
SB
131 style = "\"dotted,bold\"";
132 color = "blue";
133 weight = 10;
735a0e33 134 }
a27a5de9 135 else if (e->flags & EDGE_FALLTHRU)
735a0e33 136 {
a27a5de9
SB
137 color = "blue";
138 weight = 100;
735a0e33
UD
139 }
140
a27a5de9
SB
141 if (e->flags & EDGE_ABNORMAL)
142 color = "red";
735a0e33 143
7eba871a
SB
144 pp_printf (pp,
145 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
273a94e0 146 "[style=%s,color=%s,weight=%d,constraint=%s",
2c895bd1
SB
147 funcdef_no, e->src->index,
148 funcdef_no, e->dest->index,
7eba871a 149 style, color, weight,
357067f2
JH
150 (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
151 if (e->probability.initialized_p ())
273a94e0 152 pp_printf (pp, ",label=\"[%i%%]\"",
357067f2
JH
153 e->probability.to_reg_br_prob_base ()
154 * 100 / REG_BR_PROB_BASE);
155 pp_printf (pp, "];\n");
735a0e33 156 }
7eba871a 157 pp_flush (pp);
a27a5de9
SB
158}
159
13475df1
SB
160/* Draw all the basic blocks in the CFG in case loops are not available.
161 First compute a topological order of the blocks to get a good ranking of
162 the nodes. Then, if any nodes are not reachable from ENTRY, add them at
163 the end. */
41222ddf 164
13475df1
SB
165static void
166draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
a27a5de9 167{
0cae8d31 168 int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
a27a5de9
SB
169 int i, n;
170
7ba9e72d 171 auto_sbitmap visited (last_basic_block_for_fn (cfun));
13475df1 172 bitmap_clear (visited);
a27a5de9 173
1bef9b23 174 n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
0cae8d31
DM
175 for (i = n_basic_blocks_for_fn (fun) - n;
176 i < n_basic_blocks_for_fn (fun); i++)
13475df1 177 {
06e28de2 178 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
13475df1
SB
179 draw_cfg_node (pp, fun->funcdef_no, bb);
180 bitmap_set_bit (visited, bb->index);
181 }
182 free (rpo);
a27a5de9 183
0cae8d31 184 if (n != n_basic_blocks_for_fn (fun))
13475df1
SB
185 {
186 /* Some blocks are unreachable. We still want to dump them. */
187 basic_block bb;
188 FOR_ALL_BB_FN (bb, fun)
189 if (! bitmap_bit_p (visited, bb->index))
190 draw_cfg_node (pp, fun->funcdef_no, bb);
191 }
13475df1
SB
192}
193
194/* Draw all the basic blocks in LOOP. Print the blocks in breath-first
195 order to get a good ranking of the nodes. This function is recursive:
196 It first prints inner loops, then the body of LOOP itself. */
a27a5de9 197
13475df1
SB
198static void
199draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
99b1c316 200 class loop *loop)
13475df1
SB
201{
202 basic_block *body;
203 unsigned int i;
204 const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
205
a271b42d 206 if (loop->header != NULL
fefa31b5 207 && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
208 pp_printf (pp,
209 "\tsubgraph cluster_%d_%d {\n"
210 "\tstyle=\"filled\";\n"
211 "\tcolor=\"darkgreen\";\n"
212 "\tfillcolor=\"%s\";\n"
213 "\tlabel=\"loop %d\";\n"
214 "\tlabeljust=l;\n"
215 "\tpenwidth=2;\n",
216 funcdef_no, loop->num,
217 fillcolors[(loop_depth (loop) - 1) % 3],
218 loop->num);
219
99b1c316 220 for (class loop *inner = loop->inner; inner; inner = inner->next)
13475df1
SB
221 draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
222
a271b42d
RB
223 if (loop->header == NULL)
224 return;
225
fefa31b5 226 if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
227 body = get_loop_body (loop);
228 else
229 body = get_loop_body_in_bfs_order (loop);
230
231 for (i = 0; i < loop->num_nodes; i++)
232 {
233 basic_block bb = body[i];
234 if (bb->loop_father == loop)
235 draw_cfg_node (pp, funcdef_no, bb);
236 }
237
238 free (body);
239
fefa31b5 240 if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
241 pp_printf (pp, "\t}\n");
242}
243
244/* Draw all the basic blocks in the CFG in case the loop tree is available.
245 All loop bodys are printed in clusters. */
246
247static void
248draw_cfg_nodes (pretty_printer *pp, struct function *fun)
249{
0fc822d0
RB
250 if (loops_for_fn (fun))
251 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
13475df1
SB
252 else
253 draw_cfg_nodes_no_loops (pp, fun);
254}
255
256/* Draw all edges in the CFG. Retreating edges are drawin as not
1315099e 257 constraining, this makes the layout of the graph better. */
13475df1
SB
258
259static void
260draw_cfg_edges (pretty_printer *pp, struct function *fun)
261{
262 basic_block bb;
1315099e
TV
263
264 /* Save EDGE_DFS_BACK flag to dfs_back. */
265 auto_bitmap dfs_back;
266 edge e;
267 edge_iterator ei;
268 unsigned int idx = 0;
269 FOR_EACH_BB_FN (bb, cfun)
270 FOR_EACH_EDGE (e, ei, bb->succs)
271 {
272 if (e->flags & EDGE_DFS_BACK)
273 bitmap_set_bit (dfs_back, idx);
274 idx++;
275 }
276
a27a5de9 277 mark_dfs_back_edges ();
04a90bec 278 FOR_ALL_BB_FN (bb, cfun)
13475df1
SB
279 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
280
1315099e
TV
281 /* Restore EDGE_DFS_BACK flag from dfs_back. */
282 idx = 0;
283 FOR_EACH_BB_FN (bb, cfun)
284 FOR_EACH_EDGE (e, ei, bb->succs)
285 {
286 if (bitmap_bit_p (dfs_back, idx))
287 e->flags |= EDGE_DFS_BACK;
288 else
289 e->flags &= ~EDGE_DFS_BACK;
290 idx++;
291 }
292
13475df1
SB
293 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
294 pp_printf (pp,
295 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
296 "[style=\"invis\",constraint=true];\n",
297 fun->funcdef_no, ENTRY_BLOCK,
298 fun->funcdef_no, EXIT_BLOCK);
299 pp_flush (pp);
300}
735a0e33 301
13475df1
SB
302/* Print a graphical representation of the CFG of function FUN.
303 First print all basic blocks. Draw all edges at the end to get
304 subgraphs right for GraphViz, which requires nodes to be defined
305 before edges to cluster nodes properly. */
306
bddb7adb
RB
307void DEBUG_FUNCTION
308print_graph_cfg (FILE *fp, struct function *fun)
13475df1 309{
65f0a120 310 pretty_printer graph_slim_pp;
65f0a120
GDR
311 graph_slim_pp.buffer->stream = fp;
312 pretty_printer *const pp = &graph_slim_pp;
bddb7adb 313 const char *funcname = function_name (fun);
7088e2b0
TP
314 pp_printf (pp, "subgraph \"cluster_%s\" {\n"
315 "\tstyle=\"dashed\";\n"
316 "\tcolor=\"black\";\n"
317 "\tlabel=\"%s ()\";\n",
13475df1
SB
318 funcname, funcname);
319 draw_cfg_nodes (pp, fun);
320 draw_cfg_edges (pp, fun);
321 pp_printf (pp, "}\n");
7eba871a 322 pp_flush (pp);
bddb7adb
RB
323}
324
325/* Overload with additional flag argument. */
326
327void DEBUG_FUNCTION
1a817418 328print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
bddb7adb 329{
1a817418 330 dump_flags_t saved_dump_flags = dump_flags;
bddb7adb
RB
331 dump_flags = flags;
332 print_graph_cfg (fp, fun);
333 dump_flags = saved_dump_flags;
334}
335
336
337/* Print a graphical representation of the CFG of function FUN.
338 First print all basic blocks. Draw all edges at the end to get
339 subgraphs right for GraphViz, which requires nodes to be defined
340 before edges to cluster nodes properly. */
341
342void
343print_graph_cfg (const char *base, struct function *fun)
344{
345 FILE *fp = open_graph_file (base, "a");
346 print_graph_cfg (fp, fun);
735a0e33
UD
347 fclose (fp);
348}
349
a27a5de9
SB
350/* Start the dump of a graph. */
351static void
3fb7c699 352start_graph_dump (FILE *fp, const char *base)
a27a5de9 353{
65f0a120 354 pretty_printer graph_slim_pp;
65f0a120
GDR
355 graph_slim_pp.buffer->stream = fp;
356 pretty_printer *const pp = &graph_slim_pp;
3fb7c699
SB
357 pp_string (pp, "digraph \"");
358 pp_write_text_to_stream (pp);
359 pp_string (pp, base);
360 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
361 pp_string (pp, "\" {\n");
362 pp_string (pp, "overlap=false;\n");
363 pp_flush (pp);
a27a5de9
SB
364}
365
366/* End the dump of a graph. */
367static void
368end_graph_dump (FILE *fp)
369{
370 fputs ("}\n", fp);
371}
735a0e33
UD
372
373/* Similar as clean_dump_file, but this time for graph output files. */
374void
9f8628ba 375clean_graph_dump_file (const char *base)
735a0e33 376{
a27a5de9 377 FILE *fp = open_graph_file (base, "w");
3fb7c699 378 start_graph_dump (fp, base);
735a0e33
UD
379 fclose (fp);
380}
381
382
383/* Do final work on the graph output file. */
384void
9f8628ba 385finish_graph_dump_file (const char *base)
735a0e33 386{
a27a5de9
SB
387 FILE *fp = open_graph_file (base, "a");
388 end_graph_dump (fp);
389 fclose (fp);
735a0e33 390}
0ecf545c
MS
391
392#if __GNUC__ >= 10
393# pragma GCC diagnostic pop
394#endif