1 /* Output routines for graphical representation.
2 Copyright (C) 1998-2012
3 Free Software Foundation, Inc.
4 Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5 Rewritten for DOT output by Steven Bosscher, 2012.
7 This file is part of GCC.
9 GCC is free software; you can redistribute it and/or modify it under
10 the terms of the GNU General Public License as published by the Free
11 Software Foundation; either version 3, or (at your option) any later
14 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 You should have received a copy of the GNU General Public License
20 along with GCC; see the file COPYING3. If not see
21 <http://www.gnu.org/licenses/>. */
25 #include "coretypes.h"
26 #include "diagnostic-core.h" /* for fatal_error */
28 #include "basic-block.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 recommendatition... */
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 /* Print the output from print_insn or print_pattern with GraphViz-special
60 characters escaped as necessary. */
62 print_escaped_line (FILE *fp
, const char *buf
)
71 /* Print newlines as a left-aligned newline. */
72 fputs ("\\l\\\n", fp
);
82 /* These characters have to be escaped to work with record-shape nodes. */
91 fputs ("\\l\\\n", fp
);
94 /* Draw a basic block BB belonging to the function with FNDECL_UID
95 as its unique number. */
97 draw_cfg_node (FILE *fp
, int fndecl_uid
, basic_block bb
)
102 const char *fillcolor
;
104 if (bb
->index
== ENTRY_BLOCK
|| bb
->index
== EXIT_BLOCK
)
113 BB_PARTITION (bb
) == BB_HOT_PARTITION
? "lightpink"
114 : BB_PARTITION (bb
) == BB_COLD_PARTITION
? "lightblue"
119 "\tfn_%d_basic_block_%d [shape=%s,style=filled,fillcolor=%s,label=\"",
120 fndecl_uid
, bb
->index
, shape
, fillcolor
);
122 if (bb
->index
== ENTRY_BLOCK
)
124 else if (bb
->index
== EXIT_BLOCK
)
129 /* TODO: inter-bb stuff. */
130 FOR_BB_INSNS (bb
, insn
)
137 print_insn (buf
, insn
, 1);
138 print_escaped_line (fp
, buf
);
139 if (INSN_P (insn
) && REG_NOTES (insn
))
140 for (rtx note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
142 fprintf (fp
, " %s: ",
143 GET_REG_NOTE_NAME (REG_NOTE_KIND (note
)));
144 print_pattern (buf
, XEXP (note
, 0), 1);
145 print_escaped_line (fp
, buf
);
153 fputs ("\"];\n\n", fp
);
156 /* Draw all successor edges of a basic block BB belonging to the function
157 with FNDECL_UID as its unique number. */
159 draw_cfg_node_succ_edges (FILE *fp
, int fndecl_uid
, basic_block bb
)
163 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
165 const char *style
= "\"solid,bold\"";
166 const char *color
= "black";
169 if (e
->flags
& EDGE_FAKE
)
175 else if (e
->flags
& EDGE_DFS_BACK
)
177 style
= "\"dotted,bold\"";
181 else if (e
->flags
& EDGE_FALLTHRU
)
187 if (e
->flags
& EDGE_ABNORMAL
)
191 "\tfn_%d_basic_block_%d:s -> fn_%d_basic_block_%d:n "
192 "[style=%s,color=%s,weight=%d,constraint=%s];\n",
193 fndecl_uid
, e
->src
->index
,
194 fndecl_uid
, e
->dest
->index
,
195 style
, color
, weight
,
196 (e
->flags
& (EDGE_FAKE
| EDGE_DFS_BACK
)) ? "false" : "true");
200 /* Print a graphical representation of the CFG of function FUN.
201 Currently only supports RTL in cfgrtl or cfglayout mode, GIMPLE is TODO. */
203 print_rtl_graph_with_bb (const char *base
, tree fndecl
)
205 const char *funcname
= fndecl_name (fndecl
);
206 int fndecl_uid
= DECL_UID (fndecl
);
207 FILE *fp
= open_graph_file (base
, "a");
208 int *rpo
= XNEWVEC (int, n_basic_blocks
);
213 "subgraph \"%s\" {\n"
214 "\tcolor=\"black\";\n"
218 /* First print all basic blocks.
219 Visit the blocks in reverse post order to get a good ranking
221 n
= pre_and_rev_post_order_compute (NULL
, rpo
, true);
222 for (i
= 0; i
< n
; i
++)
223 draw_cfg_node (fp
, fndecl_uid
, BASIC_BLOCK (rpo
[i
]));
225 /* Draw all edges at the end to get subgraphs right for GraphViz,
226 which requires nodes to be defined before edges to cluster
229 Draw retreating edges as not constraining, this makes the layout
230 of the graph better. (??? Calling mark_dfs_back may change the
231 compiler's behavior when dumping, but computing back edges here
232 for ourselves is also not desirable.) */
233 mark_dfs_back_edges ();
235 draw_cfg_node_succ_edges (fp
, fndecl_uid
, bb
);
242 /* Start the dump of a graph. */
244 start_graph_dump (FILE *fp
)
246 fputs ("digraph \"\" {\n"
251 /* End the dump of a graph. */
253 end_graph_dump (FILE *fp
)
258 /* Similar as clean_dump_file, but this time for graph output files. */
260 clean_graph_dump_file (const char *base
)
262 FILE *fp
= open_graph_file (base
, "w");
263 start_graph_dump (fp
);
268 /* Do final work on the graph output file. */
270 finish_graph_dump_file (const char *base
)
272 FILE *fp
= open_graph_file (base
, "a");