2012-11-28 Oleg Raikhman <oleg@adapteva.com>
[official-gcc.git] / gcc / graph.c
blobbb1bb7b6d939e49a8984ede0cabb731650f920f0
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
12 version.
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
17 for more details.
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/>. */
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "diagnostic-core.h" /* for fatal_error */
27 #include "sbitmap.h"
28 #include "basic-block.h"
29 #include "rtl.h"
30 #include "tree.h"
31 #include "graph.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. */
41 static FILE *
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);
47 FILE *fp;
49 memcpy (buf, base, namelen);
50 memcpy (buf + namelen, graph_ext, extlen);
52 fp = fopen (buf, mode);
53 if (fp == NULL)
54 fatal_error ("can%'t open %s: %m", buf);
56 return fp;
59 /* Print the output from print_insn or print_pattern with GraphViz-special
60 characters escaped as necessary. */
61 void
62 print_escaped_line (FILE *fp, const char *buf)
64 const char *p = buf;
66 while (*p)
68 switch (*p)
70 case '\n':
71 /* Print newlines as a left-aligned newline. */
72 fputs ("\\l\\\n", fp);
73 break;
75 case '{':
76 case '}':
77 case '<':
78 case '>':
79 case '|':
80 case '"':
81 case ' ':
82 /* These characters have to be escaped to work with record-shape nodes. */
83 fputc ('\\', fp);
84 /* fall through */
85 default:
86 fputc (*p, fp);
87 break;
89 p++;
91 fputs ("\\l\\\n", fp);
94 /* Draw a basic block BB belonging to the function with FNDECL_UID
95 as its unique number. */
96 static void
97 draw_cfg_node (FILE *fp, int fndecl_uid, basic_block bb)
99 rtx insn;
100 bool first = true;
101 const char *shape;
102 const char *fillcolor;
104 if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK)
106 shape = "Mdiamond";
107 fillcolor = "white";
109 else
111 shape = "record";
112 fillcolor =
113 BB_PARTITION (bb) == BB_HOT_PARTITION ? "lightpink"
114 : BB_PARTITION (bb) == BB_COLD_PARTITION ? "lightblue"
115 : "lightgrey";
118 fprintf (fp,
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)
123 fputs ("ENTRY", fp);
124 else if (bb->index == EXIT_BLOCK)
125 fputs ("EXIT", fp);
126 else
128 fputc ('{', fp);
129 /* TODO: inter-bb stuff. */
130 FOR_BB_INSNS (bb, insn)
132 char buf[2048];
134 if (! first)
135 fputc ('|', fp);
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);
148 first = false;
150 fputc ('}', fp);
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. */
158 static void
159 draw_cfg_node_succ_edges (FILE *fp, int fndecl_uid, basic_block bb)
161 edge e;
162 edge_iterator ei;
163 FOR_EACH_EDGE (e, ei, bb->succs)
165 const char *style = "\"solid,bold\"";
166 const char *color = "black";
167 int weight = 10;
169 if (e->flags & EDGE_FAKE)
171 style = "dotted";
172 color = "green";
173 weight = 0;
175 else if (e->flags & EDGE_DFS_BACK)
177 style = "\"dotted,bold\"";
178 color = "blue";
179 weight = 10;
181 else if (e->flags & EDGE_FALLTHRU)
183 color = "blue";
184 weight = 100;
187 if (e->flags & EDGE_ABNORMAL)
188 color = "red";
190 fprintf (fp,
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. */
202 void
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);
209 basic_block bb;
210 int i, n;
212 fprintf (fp,
213 "subgraph \"%s\" {\n"
214 "\tcolor=\"black\";\n"
215 "\tlabel=\"%s\";\n",
216 funcname, funcname);
218 /* First print all basic blocks.
219 Visit the blocks in reverse post order to get a good ranking
220 of the nodes. */
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
227 nodes properly.
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 ();
234 FOR_ALL_BB (bb)
235 draw_cfg_node_succ_edges (fp, fndecl_uid, bb);
237 fputs ("\t}\n", fp);
239 fclose (fp);
242 /* Start the dump of a graph. */
243 static void
244 start_graph_dump (FILE *fp)
246 fputs ("digraph \"\" {\n"
247 "overlap=false;\n",
248 fp);
251 /* End the dump of a graph. */
252 static void
253 end_graph_dump (FILE *fp)
255 fputs ("}\n", fp);
258 /* Similar as clean_dump_file, but this time for graph output files. */
259 void
260 clean_graph_dump_file (const char *base)
262 FILE *fp = open_graph_file (base, "w");
263 start_graph_dump (fp);
264 fclose (fp);
268 /* Do final work on the graph output file. */
269 void
270 finish_graph_dump_file (const char *base)
272 FILE *fp = open_graph_file (base, "a");
273 end_graph_dump (fp);
274 fclose (fp);