]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/graph.c
Eliminate FOR_EACH_BB_REVERSE macro.
[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
2c895bd1 59/* Draw a basic block BB belonging to the function with FUNCDEF_NO
a27a5de9
SB
60 as its unique number. */
61static void
2c895bd1 62draw_cfg_node (pretty_printer *pp, int funcdef_no, basic_block bb)
a27a5de9 63{
a27a5de9
SB
64 const char *shape;
65 const char *fillcolor;
735a0e33 66
a27a5de9 67 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
735a0e33 68 {
a27a5de9
SB
69 shape = "Mdiamond";
70 fillcolor = "white";
735a0e33 71 }
735a0e33 72 else
735a0e33 73 {
a27a5de9
SB
74 shape = "record";
75 fillcolor =
76 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
77 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
78 : "lightgrey";
735a0e33 79 }
735a0e33 80
7eba871a
SB
81 pp_printf (pp,
82 "\tfn_%d_basic_block_%d "
83 "[shape=%s,style=filled,fillcolor=%s,label=\"",
2c895bd1 84 funcdef_no, bb->index, shape, fillcolor);
735a0e33 85
a27a5de9 86 if (bb->index == ENTRY_BLOCK)
7eba871a 87 pp_string (pp, "ENTRY");
a27a5de9 88 else if (bb->index == EXIT_BLOCK)
7eba871a 89 pp_string (pp, "EXIT");
a27a5de9 90 else
735a0e33 91 {
07838b13 92 pp_left_brace (pp);
7eba871a 93 pp_write_text_to_stream (pp);
2c895bd1 94 dump_bb_for_graph (pp, bb);
07838b13 95 pp_right_brace (pp);
735a0e33 96 }
a27a5de9 97
7eba871a
SB
98 pp_string (pp, "\"];\n\n");
99 pp_flush (pp);
735a0e33
UD
100}
101
a27a5de9 102/* Draw all successor edges of a basic block BB belonging to the function
2c895bd1 103 with FUNCDEF_NO as its unique number. */
735a0e33 104static void
2c895bd1 105draw_cfg_node_succ_edges (pretty_printer *pp, int funcdef_no, basic_block bb)
735a0e33 106{
a27a5de9
SB
107 edge e;
108 edge_iterator ei;
109 FOR_EACH_EDGE (e, ei, bb->succs)
735a0e33 110 {
a27a5de9
SB
111 const char *style = "\"solid,bold\"";
112 const char *color = "black";
113 int weight = 10;
735a0e33 114
a27a5de9 115 if (e->flags & EDGE_FAKE)
735a0e33 116 {
a27a5de9
SB
117 style = "dotted";
118 color = "green";
119 weight = 0;
735a0e33 120 }
a27a5de9 121 else if (e->flags & EDGE_DFS_BACK)
735a0e33 122 {
a27a5de9
SB
123 style = "\"dotted,bold\"";
124 color = "blue";
125 weight = 10;
735a0e33 126 }
a27a5de9 127 else if (e->flags & EDGE_FALLTHRU)
735a0e33 128 {
a27a5de9
SB
129 color = "blue";
130 weight = 100;
735a0e33
UD
131 }
132
a27a5de9
SB
133 if (e->flags & EDGE_ABNORMAL)
134 color = "red";
735a0e33 135
7eba871a
SB
136 pp_printf (pp,
137 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
473b1e05 138 "[style=%s,color=%s,weight=%d,constraint=%s, label=\"[%i%%]\"];\n",
2c895bd1
SB
139 funcdef_no, e->src->index,
140 funcdef_no, e->dest->index,
7eba871a 141 style, color, weight,
473b1e05
XDL
142 (e->flags & (EDGE_FAKE | EDGE_DFS_BACK)) ? "false" : "true",
143 e->probability * 100 / REG_BR_PROB_BASE);
735a0e33 144 }
7eba871a 145 pp_flush (pp);
a27a5de9
SB
146}
147
13475df1
SB
148/* Draw all the basic blocks in the CFG in case loops are not available.
149 First compute a topological order of the blocks to get a good ranking of
150 the nodes. Then, if any nodes are not reachable from ENTRY, add them at
151 the end. */
41222ddf 152
13475df1
SB
153static void
154draw_cfg_nodes_no_loops (pretty_printer *pp, struct function *fun)
a27a5de9 155{
0cae8d31 156 int *rpo = XNEWVEC (int, n_basic_blocks_for_fn (fun));
a27a5de9 157 int i, n;
13475df1 158 sbitmap visited;
a27a5de9 159
8b1c6fd7 160 visited = sbitmap_alloc (last_basic_block_for_fn (cfun));
13475df1 161 bitmap_clear (visited);
a27a5de9 162
1bef9b23 163 n = pre_and_rev_post_order_compute_fn (fun, NULL, rpo, true);
0cae8d31
DM
164 for (i = n_basic_blocks_for_fn (fun) - n;
165 i < n_basic_blocks_for_fn (fun); i++)
13475df1 166 {
06e28de2 167 basic_block bb = BASIC_BLOCK_FOR_FN (cfun, rpo[i]);
13475df1
SB
168 draw_cfg_node (pp, fun->funcdef_no, bb);
169 bitmap_set_bit (visited, bb->index);
170 }
171 free (rpo);
a27a5de9 172
0cae8d31 173 if (n != n_basic_blocks_for_fn (fun))
13475df1
SB
174 {
175 /* Some blocks are unreachable. We still want to dump them. */
176 basic_block bb;
177 FOR_ALL_BB_FN (bb, fun)
178 if (! bitmap_bit_p (visited, bb->index))
179 draw_cfg_node (pp, fun->funcdef_no, bb);
180 }
181
182 sbitmap_free (visited);
183}
184
185/* Draw all the basic blocks in LOOP. Print the blocks in breath-first
186 order to get a good ranking of the nodes. This function is recursive:
187 It first prints inner loops, then the body of LOOP itself. */
a27a5de9 188
13475df1
SB
189static void
190draw_cfg_nodes_for_loop (pretty_printer *pp, int funcdef_no,
191 struct loop *loop)
192{
193 basic_block *body;
194 unsigned int i;
195 const char *fillcolors[3] = { "grey88", "grey77", "grey66" };
196
a271b42d 197 if (loop->header != NULL
fefa31b5 198 && loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
199 pp_printf (pp,
200 "\tsubgraph cluster_%d_%d {\n"
201 "\tstyle=\"filled\";\n"
202 "\tcolor=\"darkgreen\";\n"
203 "\tfillcolor=\"%s\";\n"
204 "\tlabel=\"loop %d\";\n"
205 "\tlabeljust=l;\n"
206 "\tpenwidth=2;\n",
207 funcdef_no, loop->num,
208 fillcolors[(loop_depth (loop) - 1) % 3],
209 loop->num);
210
211 for (struct loop *inner = loop->inner; inner; inner = inner->next)
212 draw_cfg_nodes_for_loop (pp, funcdef_no, inner);
213
a271b42d
RB
214 if (loop->header == NULL)
215 return;
216
fefa31b5 217 if (loop->latch == EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
218 body = get_loop_body (loop);
219 else
220 body = get_loop_body_in_bfs_order (loop);
221
222 for (i = 0; i < loop->num_nodes; i++)
223 {
224 basic_block bb = body[i];
225 if (bb->loop_father == loop)
226 draw_cfg_node (pp, funcdef_no, bb);
227 }
228
229 free (body);
230
fefa31b5 231 if (loop->latch != EXIT_BLOCK_PTR_FOR_FN (cfun))
13475df1
SB
232 pp_printf (pp, "\t}\n");
233}
234
235/* Draw all the basic blocks in the CFG in case the loop tree is available.
236 All loop bodys are printed in clusters. */
237
238static void
239draw_cfg_nodes (pretty_printer *pp, struct function *fun)
240{
0fc822d0
RB
241 if (loops_for_fn (fun))
242 draw_cfg_nodes_for_loop (pp, fun->funcdef_no, get_loop (fun, 0));
13475df1
SB
243 else
244 draw_cfg_nodes_no_loops (pp, fun);
245}
246
247/* Draw all edges in the CFG. Retreating edges are drawin as not
248 constraining, this makes the layout of the graph better.
249 (??? Calling mark_dfs_back may change the compiler's behavior when
250 dumping, but computing back edges here for ourselves is also not
251 desirable.) */
252
253static void
254draw_cfg_edges (pretty_printer *pp, struct function *fun)
255{
256 basic_block bb;
a27a5de9
SB
257 mark_dfs_back_edges ();
258 FOR_ALL_BB (bb)
13475df1
SB
259 draw_cfg_node_succ_edges (pp, fun->funcdef_no, bb);
260
261 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
262 pp_printf (pp,
263 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
264 "[style=\"invis\",constraint=true];\n",
265 fun->funcdef_no, ENTRY_BLOCK,
266 fun->funcdef_no, EXIT_BLOCK);
267 pp_flush (pp);
268}
735a0e33 269
13475df1
SB
270/* Print a graphical representation of the CFG of function FUN.
271 First print all basic blocks. Draw all edges at the end to get
272 subgraphs right for GraphViz, which requires nodes to be defined
273 before edges to cluster nodes properly. */
274
275void
276print_graph_cfg (const char *base, struct function *fun)
277{
278 const char *funcname = function_name (fun);
279 FILE *fp = open_graph_file (base, "a");
65f0a120 280 pretty_printer graph_slim_pp;
65f0a120
GDR
281 graph_slim_pp.buffer->stream = fp;
282 pretty_printer *const pp = &graph_slim_pp;
13475df1
SB
283 pp_printf (pp, "subgraph \"%s\" {\n"
284 "\tcolor=\"black\";\n"
285 "\tlabel=\"%s\";\n",
286 funcname, funcname);
287 draw_cfg_nodes (pp, fun);
288 draw_cfg_edges (pp, fun);
289 pp_printf (pp, "}\n");
7eba871a 290 pp_flush (pp);
735a0e33
UD
291 fclose (fp);
292}
293
a27a5de9
SB
294/* Start the dump of a graph. */
295static void
3fb7c699 296start_graph_dump (FILE *fp, const char *base)
a27a5de9 297{
65f0a120 298 pretty_printer graph_slim_pp;
65f0a120
GDR
299 graph_slim_pp.buffer->stream = fp;
300 pretty_printer *const pp = &graph_slim_pp;
3fb7c699
SB
301 pp_string (pp, "digraph \"");
302 pp_write_text_to_stream (pp);
303 pp_string (pp, base);
304 pp_write_text_as_dot_label_to_stream (pp, /*for_record=*/false);
305 pp_string (pp, "\" {\n");
306 pp_string (pp, "overlap=false;\n");
307 pp_flush (pp);
a27a5de9
SB
308}
309
310/* End the dump of a graph. */
311static void
312end_graph_dump (FILE *fp)
313{
314 fputs ("}\n", fp);
315}
735a0e33
UD
316
317/* Similar as clean_dump_file, but this time for graph output files. */
318void
9f8628ba 319clean_graph_dump_file (const char *base)
735a0e33 320{
a27a5de9 321 FILE *fp = open_graph_file (base, "w");
3fb7c699 322 start_graph_dump (fp, base);
735a0e33
UD
323 fclose (fp);
324}
325
326
327/* Do final work on the graph output file. */
328void
9f8628ba 329finish_graph_dump_file (const char *base)
735a0e33 330{
a27a5de9
SB
331 FILE *fp = open_graph_file (base, "a");
332 end_graph_dump (fp);
333 fclose (fp);
735a0e33 334}