1 /* Output routines for graphical representation.
2 Copyright (C) 1998-2013 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"
25 #include "diagnostic-core.h" /* for fatal_error */
27 #include "basic-block.h"
31 #include "pretty-print.h"
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
36 ignore that recommendation... */
37 static const char *const graph_ext
= ".dot";
39 /* Open a file with MODE for dumping our graph to.
40 Return the file pointer. */
42 open_graph_file (const char *base
, const char *mode
)
44 size_t namelen
= strlen (base
);
45 size_t extlen
= strlen (graph_ext
) + 1;
46 char *buf
= XALLOCAVEC (char, namelen
+ extlen
);
49 memcpy (buf
, base
, namelen
);
50 memcpy (buf
+ namelen
, graph_ext
, extlen
);
52 fp
= fopen (buf
, mode
);
54 fatal_error ("can%'t open %s: %m", buf
);
59 /* Return a pretty-print buffer for output to file FP. */
61 static pretty_printer
*
62 init_graph_slim_pretty_print (FILE *fp
)
64 static bool initialized
= false;
65 static pretty_printer graph_slim_pp
;
69 pp_construct (&graph_slim_pp
, /*prefix=*/NULL
, /*linewidth=*/0);
73 gcc_assert (! pp_last_position_in_text (&graph_slim_pp
));
75 graph_slim_pp
.buffer
->stream
= fp
;
76 return &graph_slim_pp
;
79 /* Draw a basic block BB belonging to the function with FUNCDEF_NO
80 as its unique number. */
82 draw_cfg_node (pretty_printer
*pp
, int funcdef_no
, basic_block bb
)
85 const char *fillcolor
;
87 if (bb
->index
== ENTRY_BLOCK
|| bb
->index
== EXIT_BLOCK
)
96 BB_PARTITION (bb
) == BB_HOT_PARTITION
? "lightpink"
97 : BB_PARTITION (bb
) == BB_COLD_PARTITION
? "lightblue"
102 "\tfn_%d_basic_block_%d "
103 "[shape=%s,style=filled,fillcolor=%s,label=\"",
104 funcdef_no
, bb
->index
, shape
, fillcolor
);
106 if (bb
->index
== ENTRY_BLOCK
)
107 pp_string (pp
, "ENTRY");
108 else if (bb
->index
== EXIT_BLOCK
)
109 pp_string (pp
, "EXIT");
112 pp_character (pp
, '{');
113 pp_write_text_to_stream (pp
);
114 dump_bb_for_graph (pp
, bb
);
115 pp_character (pp
, '}');
118 pp_string (pp
, "\"];\n\n");
122 /* Draw all successor edges of a basic block BB belonging to the function
123 with FUNCDEF_NO as its unique number. */
125 draw_cfg_node_succ_edges (pretty_printer
*pp
, int funcdef_no
, basic_block bb
)
129 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
131 const char *style
= "\"solid,bold\"";
132 const char *color
= "black";
135 if (e
->flags
& EDGE_FAKE
)
141 else if (e
->flags
& EDGE_DFS_BACK
)
143 style
= "\"dotted,bold\"";
147 else if (e
->flags
& EDGE_FALLTHRU
)
153 if (e
->flags
& EDGE_ABNORMAL
)
157 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
158 "[style=%s,color=%s,weight=%d,constraint=%s];\n",
159 funcdef_no
, e
->src
->index
,
160 funcdef_no
, e
->dest
->index
,
161 style
, color
, weight
,
162 (e
->flags
& (EDGE_FAKE
| EDGE_DFS_BACK
)) ? "false" : "true");
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
173 draw_cfg_nodes_no_loops (pretty_printer
*pp
, struct function
*fun
)
175 int *rpo
= XNEWVEC (int, n_basic_blocks_for_function (fun
));
179 visited
= sbitmap_alloc (last_basic_block
);
180 bitmap_clear (visited
);
182 /* FIXME: pre_and_rev_post_order_compute only works if fun == cfun. */
183 n
= pre_and_rev_post_order_compute (NULL
, rpo
, true);
184 for (i
= 0; i
< n
; i
++)
186 basic_block bb
= BASIC_BLOCK (rpo
[i
]);
187 draw_cfg_node (pp
, fun
->funcdef_no
, bb
);
188 bitmap_set_bit (visited
, bb
->index
);
192 if (n
!= n_basic_blocks_for_function (fun
))
194 /* Some blocks are unreachable. We still want to dump them. */
196 FOR_ALL_BB_FN (bb
, fun
)
197 if (! bitmap_bit_p (visited
, bb
->index
))
198 draw_cfg_node (pp
, fun
->funcdef_no
, bb
);
201 sbitmap_free (visited
);
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. */
209 draw_cfg_nodes_for_loop (pretty_printer
*pp
, int funcdef_no
,
214 const char *fillcolors
[3] = { "grey88", "grey77", "grey66" };
216 if (loop
->header
!= NULL
217 && loop
->latch
!= EXIT_BLOCK_PTR
)
219 "\tsubgraph cluster_%d_%d {\n"
220 "\tstyle=\"filled\";\n"
221 "\tcolor=\"darkgreen\";\n"
222 "\tfillcolor=\"%s\";\n"
223 "\tlabel=\"loop %d\";\n"
226 funcdef_no
, loop
->num
,
227 fillcolors
[(loop_depth (loop
) - 1) % 3],
230 for (struct loop
*inner
= loop
->inner
; inner
; inner
= inner
->next
)
231 draw_cfg_nodes_for_loop (pp
, funcdef_no
, inner
);
233 if (loop
->header
== NULL
)
236 if (loop
->latch
== EXIT_BLOCK_PTR
)
237 body
= get_loop_body (loop
);
239 body
= get_loop_body_in_bfs_order (loop
);
241 for (i
= 0; i
< loop
->num_nodes
; i
++)
243 basic_block bb
= body
[i
];
244 if (bb
->loop_father
== loop
)
245 draw_cfg_node (pp
, funcdef_no
, bb
);
250 if (loop
->latch
!= EXIT_BLOCK_PTR
)
251 pp_printf (pp
, "\t}\n");
254 /* Draw all the basic blocks in the CFG in case the loop tree is available.
255 All loop bodys are printed in clusters. */
258 draw_cfg_nodes (pretty_printer
*pp
, struct function
*fun
)
260 /* ??? This x_current_loops should be enapsulated. */
261 if (fun
->x_current_loops
)
262 draw_cfg_nodes_for_loop (pp
, fun
->funcdef_no
,
263 fun
->x_current_loops
->tree_root
);
265 draw_cfg_nodes_no_loops (pp
, fun
);
268 /* Draw all edges in the CFG. Retreating edges are drawin as not
269 constraining, this makes the layout of the graph better.
270 (??? Calling mark_dfs_back may change the compiler's behavior when
271 dumping, but computing back edges here for ourselves is also not
275 draw_cfg_edges (pretty_printer
*pp
, struct function
*fun
)
278 mark_dfs_back_edges ();
280 draw_cfg_node_succ_edges (pp
, fun
->funcdef_no
, bb
);
282 /* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
284 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
285 "[style=\"invis\",constraint=true];\n",
286 fun
->funcdef_no
, ENTRY_BLOCK
,
287 fun
->funcdef_no
, EXIT_BLOCK
);
291 /* Print a graphical representation of the CFG of function FUN.
292 First print all basic blocks. Draw all edges at the end to get
293 subgraphs right for GraphViz, which requires nodes to be defined
294 before edges to cluster nodes properly. */
297 print_graph_cfg (const char *base
, struct function
*fun
)
299 const char *funcname
= function_name (fun
);
300 FILE *fp
= open_graph_file (base
, "a");
301 pretty_printer
*pp
= init_graph_slim_pretty_print (fp
);
302 pp_printf (pp
, "subgraph \"%s\" {\n"
303 "\tcolor=\"black\";\n"
306 draw_cfg_nodes (pp
, fun
);
307 draw_cfg_edges (pp
, fun
);
308 pp_printf (pp
, "}\n");
313 /* Start the dump of a graph. */
315 start_graph_dump (FILE *fp
, const char *base
)
317 pretty_printer
*pp
= init_graph_slim_pretty_print (fp
);
318 pp_string (pp
, "digraph \"");
319 pp_write_text_to_stream (pp
);
320 pp_string (pp
, base
);
321 pp_write_text_as_dot_label_to_stream (pp
, /*for_record=*/false);
322 pp_string (pp
, "\" {\n");
323 pp_string (pp
, "overlap=false;\n");
327 /* End the dump of a graph. */
329 end_graph_dump (FILE *fp
)
334 /* Similar as clean_dump_file, but this time for graph output files. */
336 clean_graph_dump_file (const char *base
)
338 FILE *fp
= open_graph_file (base
, "w");
339 start_graph_dump (fp
, base
);
344 /* Do final work on the graph output file. */
346 finish_graph_dump_file (const char *base
)
348 FILE *fp
= open_graph_file (base
, "a");