]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/graph.c
Optimize ODR enum streaming
[thirdparty/gcc.git] / gcc / graph.c
1 /* Output routines for graphical representation.
2 Copyright (C) 1998-2020 Free Software Foundation, Inc.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4 Rewritten for DOT output by Steven Bosscher, 2012.
5
6 This file is part of GCC.
7
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
11 version.
12
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
16 for more details.
17
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/>. */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "cfghooks.h"
27 #include "pretty-print.h"
28 #include "diagnostic-core.h" /* for fatal_error */
29 #include "cfganal.h"
30 #include "cfgloop.h"
31 #include "graph.h"
32 #include "dumpfile.h"
33
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";
39
40 /* Open a file with MODE for dumping our graph to.
41 Return the file pointer. */
42 static FILE *
43 open_graph_file (const char *base, const char *mode)
44 {
45 size_t namelen = strlen (base);
46 size_t extlen = strlen (graph_ext) + 1;
47 char *buf = XALLOCAVEC (char, namelen + extlen);
48 FILE *fp;
49
50 memcpy (buf, base, namelen);
51 memcpy (buf + namelen, graph_ext, extlen);
52
53 fp = fopen (buf, mode);
54 if (fp == NULL)
55 fatal_error (input_location, "cannot open %s: %m", buf);
56
57 return fp;
58 }
59
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
67 /* Draw a basic block BB belonging to the function with FUNCDEF_NO
68 as its unique number. */
69 static void
70 draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
71 {
72 const char *shape;
73 const char *fillcolor;
74
75 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
76 {
77 shape = "Mdiamond";
78 fillcolor = "white";
79 }
80 else
81 {
82 shape = "record";
83 fillcolor =
84 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
85 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
86 : "lightgrey";
87 }
88
89 pp_printf (pp,
90 "\tfn_%d_basic_block_%d "
91 "[shape=%s,style=filled,fillcolor=%s,label=\"",
92 funcdef_no, bb->index, shape, fillcolor);
93
94 if (bb->index == ENTRY_BLOCK)
95 pp_string (pp, "ENTRY");
96 else if (bb->index == EXIT_BLOCK)
97 pp_string (pp, "EXIT");
98 else
99 {
100 pp_left_brace (pp);
101 pp_write_text_to_stream (pp);
102 dump_bb_for_graph (pp, bb);
103 pp_right_brace (pp);
104 }
105
106 pp_string (pp, "\"];\n\n");
107 pp_flush (pp);
108 }
109
110 /* Draw all successor edges of a basic block BB belonging to the function
111 with FUNCDEF_NO as its unique number. */
112 static void
113 draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
114 {
115 edge e;
116 edge_iterator ei;
117 FOR_EACH_EDGE (e, ei, bb->succs)
118 {
119 const char *style = "\"solid,bold\"";
120 const char *color = "black";
121 int weight = 10;
122
123 if (e->flags & EDGE_FAKE)
124 {
125 style = "dotted";
126 color = "green";
127 weight = 0;
128 }
129 else if (e->flags & EDGE_DFS_BACK)
130 {
131 style = "\"dotted,bold\"";
132 color = "blue";
133 weight = 10;
134 }
135 else if (e->flags & EDGE_FALLTHRU)
136 {
137 color = "blue";
138 weight = 100;
139 }
140
141 if (e->flags & EDGE_ABNORMAL)
142 color = "red";
143
144 pp_printf (pp,
145 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
146 "[style=%s,color=%s,weight=%d,constraint=%s",
147 funcdef_no, e->src->index,
148 funcdef_no, e->dest->index,
149 style, color, weight,
150 (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
151 if (e->probability.initialized_p ())
152 pp_printf (pp, ",label=\"[%i%%]\"",
153 e->probability.to_reg_br_prob_base ()
154 * 100 / REG_BR_PROB_BASE);
155 pp_printf (pp, "];\n");
156 }
157 pp_flush (pp);
158 }
159
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. */
164
165 static void
166 draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
167 {
168 int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
169 int i, n;
170
171 auto_sbitmap visited (last_basic_block_for_fn (cfun));
172 bitmap_clear (visited);
173
174 n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
175 for (i = n_basic_blocks_for_fn (fun) - n;
176 i < n_basic_blocks_for_fn (fun); i++)
177 {
178 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
179 draw_cfg_node (pp, fun->funcdef_no, bb);
180 bitmap_set_bit (visited, bb->index);
181 }
182 free (rpo);
183
184 if (n != n_basic_blocks_for_fn (fun))
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 }
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. */
197
198 static void
199 draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
200 class loop *loop)
201 {
202 basic_block *body;
203 unsigned int i;
204 const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
205
206 if (loop->header != NULL
207 && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
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
220 for (class loop *inner = loop->inner; inner; inner = inner->next)
221 draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
222
223 if (loop->header == NULL)
224 return;
225
226 if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
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
240 if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
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
247 static void
248 draw_cfg_nodes (pretty_printer *pp, struct function *fun)
249 {
250 if (loops_for_fn (fun))
251 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
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
257 constraining, this makes the layout of the graph better. */
258
259 static void
260 draw_cfg_edges (pretty_printer *pp, struct function *fun)
261 {
262 basic_block bb;
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
277 mark_dfs_back_edges ();
278 FOR_ALL_BB_FN (bb, cfun)
279 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
280
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
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 }
301
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
307 void DEBUG_FUNCTION
308 print_graph_cfg (FILE *fp, struct function *fun)
309 {
310 pretty_printer graph_slim_pp;
311 graph_slim_pp.buffer->stream = fp;
312 pretty_printer *const pp = &graph_slim_pp;
313 const char *funcname = function_name (fun);
314 pp_printf (pp, "subgraph \"cluster_%s\" {\n"
315 "\tstyle=\"dashed\";\n"
316 "\tcolor=\"black\";\n"
317 "\tlabel=\"%s ()\";\n",
318 funcname, funcname);
319 draw_cfg_nodes (pp, fun);
320 draw_cfg_edges (pp, fun);
321 pp_printf (pp, "}\n");
322 pp_flush (pp);
323 }
324
325 /* Overload with additional flag argument. */
326
327 void DEBUG_FUNCTION
328 print_graph_cfg (FILE *fp, struct function *fun, dump_flags_t flags)
329 {
330 dump_flags_t saved_dump_flags = dump_flags;
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
342 void
343 print_graph_cfg (const char *base, struct function *fun)
344 {
345 FILE *fp = open_graph_file (base, "a");
346 print_graph_cfg (fp, fun);
347 fclose (fp);
348 }
349
350 /* Start the dump of a graph. */
351 static void
352 start_graph_dump (FILE *fp, const char *base)
353 {
354 pretty_printer graph_slim_pp;
355 graph_slim_pp.buffer->stream = fp;
356 pretty_printer *const pp = &graph_slim_pp;
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);
364 }
365
366 /* End the dump of a graph. */
367 static void
368 end_graph_dump (FILE *fp)
369 {
370 fputs ("}\n", fp);
371 }
372
373 /* Similar as clean_dump_file, but this time for graph output files. */
374 void
375 clean_graph_dump_file (const char *base)
376 {
377 FILE *fp = open_graph_file (base, "w");
378 start_graph_dump (fp, base);
379 fclose (fp);
380 }
381
382
383 /* Do final work on the graph output file. */
384 void
385 finish_graph_dump_file (const char *base)
386 {
387 FILE *fp = open_graph_file (base, "a");
388 end_graph_dump (fp);
389 fclose (fp);
390 }
391
392 #if __GNUC__ >= 10
393 # pragma GCC diagnostic pop
394 #endif