]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/graph.c
re PR fortran/53818 (-finit-local-zero -fno-automatic: Function result cannot have...
[thirdparty/gcc.git] / gcc / graph.c
CommitLineData
735a0e33 1/* Output routines for graphical representation.
d1e082c2 2 Copyright (C) 1998-2013 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"
a27a5de9 25#include "diagnostic-core.h" /* for fatal_error */
13475df1 26#include "sbitmap.h"
735a0e33 27#include "basic-block.h"
13475df1 28#include "cfgloop.h"
6a2cc2ac 29#include "graph.h"
41222ddf 30#include "dumpfile.h"
7eba871a 31#include "pretty-print.h"
735a0e33 32
a27a5de9
SB
33/* DOT files with the .dot extension are recognized as document templates
34 by a well-known piece of word processing software out of Redmond, WA.
35 Therefore some recommend using the .gv extension instead. Obstinately
13475df1 36 ignore that recommendation... */
a27a5de9 37static const char *const graph_ext = ".dot";
208d8b55 38
a27a5de9
SB
39/* Open a file with MODE for dumping our graph to.
40 Return the file pointer. */
41static FILE *
42open_graph_file (const char *base, const char *mode)
735a0e33 43{
a27a5de9
SB
44 size_t namelen = strlen (base);
45 size_t extlen = strlen (graph_ext) + 1;
46 char *buf = XALLOCAVEC (char, namelen + extlen);
47 FILE *fp;
735a0e33 48
a27a5de9
SB
49 memcpy (buf, base, namelen);
50 memcpy (buf + namelen, graph_ext, extlen);
735a0e33 51
a27a5de9
SB
52 fp = fopen (buf, mode);
53 if (fp == NULL)
54 fatal_error ("can%'t open %s: %m", buf);
735a0e33 55
a27a5de9 56 return fp;
735a0e33
UD
57}
58
7eba871a
SB
59/* Return a pretty-print buffer for output to file FP. */
60
61static pretty_printer *
62init_graph_slim_pretty_print (FILE *fp)
735a0e33 63{
7eba871a
SB
64 static bool initialized = false;
65 static pretty_printer graph_slim_pp;
a27a5de9 66
7eba871a 67 if (! initialized)
735a0e33 68 {
7eba871a
SB
69 pp_construct (&graph_slim_pp, /*prefix=*/NULL, /*linewidth=*/0);
70 initialized = true;
735a0e33 71 }
7eba871a
SB
72 else
73 gcc_assert (! pp_last_position_in_text (&graph_slim_pp));
74
75 graph_slim_pp.buffer->stream = fp;
76 return &graph_slim_pp;
a27a5de9 77}
735a0e33 78
2c895bd1 79/* Draw a basic block BB belonging to the function with FUNCDEF_NO
a27a5de9
SB
80 as its unique number. */
81static void
2c895bd1 82draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
a27a5de9 83{
a27a5de9
SB
84 const char *shape;
85 const char *fillcolor;
735a0e33 86
a27a5de9 87 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
735a0e33 88 {
a27a5de9
SB
89 shape = "Mdiamond";
90 fillcolor = "white";
735a0e33 91 }
735a0e33 92 else
735a0e33 93 {
a27a5de9
SB
94 shape = "record";
95 fillcolor =
96 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
97 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
98 : "lightgrey";
735a0e33 99 }
735a0e33 100
7eba871a
SB
101 pp_printf (pp,
102 "\tfn_%d_basic_block_%d "
103 "[shape=%s,style=filled,fillcolor=%s,label=\"",
2c895bd1 104 funcdef_no, bb->index, shape, fillcolor);
735a0e33 105
a27a5de9 106 if (bb->index == ENTRY_BLOCK)
7eba871a 107 pp_string (pp, "ENTRY");
a27a5de9 108 else if (bb->index == EXIT_BLOCK)
7eba871a 109 pp_string (pp, "EXIT");
a27a5de9 110 else
735a0e33 111 {
7eba871a
SB
112 pp_character (pp, '{');
113 pp_write_text_to_stream (pp);
2c895bd1 114 dump_bb_for_graph (pp, bb);
7eba871a 115 pp_character (pp, '}');
735a0e33 116 }
a27a5de9 117
7eba871a
SB
118 pp_string (pp, "\"];\n\n");
119 pp_flush (pp);
735a0e33
UD
120}
121
a27a5de9 122/* Draw all successor edges of a basic block BB belonging to the function
2c895bd1 123 with FUNCDEF_NO as its unique number. */
735a0e33 124static void
2c895bd1 125draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
735a0e33 126{
a27a5de9
SB
127 edge e;
128 edge_iterator ei;
129 FOR_EACH_EDGE (e, ei, bb->succs)
735a0e33 130 {
a27a5de9
SB
131 const char *style = "\"solid,bold\"";
132 const char *color = "black";
133 int weight = 10;
735a0e33 134
a27a5de9 135 if (e->flags & EDGE_FAKE)
735a0e33 136 {
a27a5de9
SB
137 style = "dotted";
138 color = "green";
139 weight = 0;
735a0e33 140 }
a27a5de9 141 else if (e->flags & EDGE_DFS_BACK)
735a0e33 142 {
a27a5de9
SB
143 style = "\"dotted,bold\"";
144 color = "blue";
145 weight = 10;
735a0e33 146 }
a27a5de9 147 else if (e->flags & EDGE_FALLTHRU)
735a0e33 148 {
a27a5de9
SB
149 color = "blue";
150 weight = 100;
735a0e33
UD
151 }
152
a27a5de9
SB
153 if (e->flags & EDGE_ABNORMAL)
154 color = "red";
735a0e33 155
7eba871a
SB
156 pp_printf (pp,
157 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
158 "[style=%s,color=%s,weight=%d,constraint=%s];\n",
2c895bd1
SB
159 funcdef_no, e->src->index,
160 funcdef_no, e->dest->index,
7eba871a
SB
161 style, color, weight,
162 (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true");
735a0e33 163 }
7eba871a 164 pp_flush (pp);
a27a5de9
SB
165}
166
13475df1
SB
167/* Draw all the basic blocks in the CFG in case loops are not available.
168 First compute a topological order of the blocks to get a good ranking of
169 the nodes. Then, if any nodes are not reachable from ENTRY, add them at
170 the end. */
41222ddf 171
13475df1
SB
172static void
173draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
a27a5de9 174{
13475df1 175 int *rpo = XNEWVEC (int, n_basic_blocks_for_function (fun));
a27a5de9 176 int i, n;
13475df1 177 sbitmap visited;
a27a5de9 178
13475df1
SB
179 visited = sbitmap_alloc (last_basic_block);
180 bitmap_clear (visited);
a27a5de9 181
13475df1 182 /* FIXME: pre_and_rev_post_order_compute only works if fun == cfun. */
a27a5de9
SB
183 n = pre_and_rev_post_order_compute (NULL, rpo, true);
184 for (i = 0; i < n; i++)
13475df1
SB
185 {
186 basic_block bb = BASIC_BLOCK (rpo[i]);
187 draw_cfg_node (pp, fun->funcdef_no, bb);
188 bitmap_set_bit (visited, bb->index);
189 }
190 free (rpo);
a27a5de9 191
13475df1
SB
192 if (n != n_basic_blocks_for_function (fun))
193 {
194 /* Some blocks are unreachable. We still want to dump them. */
195 basic_block bb;
196 FOR_ALL_BB_FN (bb, fun)
197 if (! bitmap_bit_p (visited, bb->index))
198 draw_cfg_node (pp, fun->funcdef_no, bb);
199 }
200
201 sbitmap_free (visited);
202}
203
204/* Draw all the basic blocks in LOOP. Print the blocks in breath-first
205 order to get a good ranking of the nodes. This function is recursive:
206 It first prints inner loops, then the body of LOOP itself. */
a27a5de9 207
13475df1
SB
208static void
209draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
210 struct loop *loop)
211{
212 basic_block *body;
213 unsigned int i;
214 const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
215
216 if (loop->latch != EXIT_BLOCK_PTR)
217 pp_printf (pp,
218 "\tsubgraph cluster_%d_%d {\n"
219 "\tstyle=\"filled\";\n"
220 "\tcolor=\"darkgreen\";\n"
221 "\tfillcolor=\"%s\";\n"
222 "\tlabel=\"loop %d\";\n"
223 "\tlabeljust=l;\n"
224 "\tpenwidth=2;\n",
225 funcdef_no, loop->num,
226 fillcolors[(loop_depth (loop) - 1) % 3],
227 loop->num);
228
229 for (struct loop *inner = loop->inner; inner; inner = inner->next)
230 draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
231
232 if (loop->latch == EXIT_BLOCK_PTR)
233 body = get_loop_body (loop);
234 else
235 body = get_loop_body_in_bfs_order (loop);
236
237 for (i = 0; i < loop->num_nodes; i++)
238 {
239 basic_block bb = body[i];
240 if (bb->loop_father == loop)
241 draw_cfg_node (pp, funcdef_no, bb);
242 }
243
244 free (body);
245
246 if (loop->latch != EXIT_BLOCK_PTR)
247 pp_printf (pp, "\t}\n");
248}
249
250/* Draw all the basic blocks in the CFG in case the loop tree is available.
251 All loop bodys are printed in clusters. */
252
253static void
254draw_cfg_nodes (pretty_printer *pp, struct function *fun)
255{
256 /* ??? This x_current_loops should be enapsulated. */
257 if (fun->x_current_loops)
258 draw_cfg_nodes_for_loop (pp, fun->funcdef_no,
259 fun->x_current_loops->tree_root);
260 else
261 draw_cfg_nodes_no_loops (pp, fun);
262}
263
264/* Draw all edges in the CFG. Retreating edges are drawin as not
265 constraining, this makes the layout of the graph better.
266 (??? Calling mark_dfs_back may change the compiler's behavior when
267 dumping, but computing back edges here for ourselves is also not
268 desirable.) */
269
270static void
271draw_cfg_edges (pretty_printer *pp, struct function *fun)
272{
273 basic_block bb;
a27a5de9
SB
274 mark_dfs_back_edges ();
275 FOR_ALL_BB (bb)
13475df1
SB
276 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
277
278 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
279 pp_printf (pp,
280 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
281 "[style=\"invis\",constraint=true];\n",
282 fun->funcdef_no, ENTRY_BLOCK,
283 fun->funcdef_no, EXIT_BLOCK);
284 pp_flush (pp);
285}
735a0e33 286
13475df1
SB
287/* Print a graphical representation of the CFG of function FUN.
288 First print all basic blocks. Draw all edges at the end to get
289 subgraphs right for GraphViz, which requires nodes to be defined
290 before edges to cluster nodes properly. */
291
292void
293print_graph_cfg (const char *base, struct function *fun)
294{
295 const char *funcname = function_name (fun);
296 FILE *fp = open_graph_file (base, "a");
297 pretty_printer *pp = init_graph_slim_pretty_print (fp);
298 pp_printf (pp, "subgraph \"%s\" {\n"
299 "\tcolor=\"black\";\n"
300 "\tlabel=\"%s\";\n",
301 funcname, funcname);
302 draw_cfg_nodes (pp, fun);
303 draw_cfg_edges (pp, fun);
304 pp_printf (pp, "}\n");
7eba871a 305 pp_flush (pp);
735a0e33
UD
306 fclose (fp);
307}
308
a27a5de9
SB
309/* Start the dump of a graph. */
310static void
311start_graph_dump (FILE *fp)
312{
313 fputs ("digraph \"\" {\n"
314 "overlap=false;\n",
315 fp);
316}
317
318/* End the dump of a graph. */
319static void
320end_graph_dump (FILE *fp)
321{
322 fputs ("}\n", fp);
323}
735a0e33
UD
324
325/* Similar as clean_dump_file, but this time for graph output files. */
326void
9f8628ba 327clean_graph_dump_file (const char *base)
735a0e33 328{
a27a5de9
SB
329 FILE *fp = open_graph_file (base, "w");
330 start_graph_dump (fp);
735a0e33
UD
331 fclose (fp);
332}
333
334
335/* Do final work on the graph output file. */
336void
9f8628ba 337finish_graph_dump_file (const char *base)
735a0e33 338{
a27a5de9
SB
339 FILE *fp = open_graph_file (base, "a");
340 end_graph_dump (fp);
341 fclose (fp);
735a0e33 342}