OSDN Git Service

Clarify copyright license agreement.
[pf3gnuchains/gcc-fork.git] / gcc / graph.c
1 /* Output routines for graphical representation.
2    Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2007, 2008, 2010
3    Free Software Foundation, Inc.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
5
6 This file is part of GCC.
7
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
11 version.
12
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
16 for more details.
17
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/>.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "rtl.h"
27 #include "flags.h"
28 #include "output.h"
29 #include "function.h"
30 #include "hard-reg-set.h"
31 #include "obstack.h"
32 #include "basic-block.h"
33 #include "diagnostic-core.h"
34 #include "graph.h"
35 #include "emit-rtl.h"
36
37 static const char *const graph_ext[] =
38 {
39   /* no_graph */ "",
40   /* vcg */      ".vcg",
41 };
42
43 /* The flag to indicate if output is inside of a building block.  */
44 static int inbb = 0;
45
46 static void start_fct (FILE *);
47 static void start_bb (FILE *, int);
48 static void node_data (FILE *, rtx);
49 static void draw_edge (FILE *, int, int, int, int);
50 static void end_fct (FILE *);
51 static void end_bb (FILE *);
52
53 /* Output text for new basic block.  */
54 static void
55 start_fct (FILE *fp)
56 {
57   switch (graph_dump_format)
58     {
59     case vcg:
60       fprintf (fp, "\
61 graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
62                current_function_name (), current_function_name ());
63       break;
64     case no_graph:
65       break;
66     }
67 }
68
69 static void
70 start_bb (FILE *fp, int bb)
71 {
72 #if 0
73   reg_set_iterator rsi;
74 #endif
75
76   switch (graph_dump_format)
77     {
78     case vcg:
79       fprintf (fp, "\
80 graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
81 label: \"basic block %d",
82                current_function_name (), bb, bb);
83       inbb = 1; /* Now We are inside of a building block.  */
84       break;
85     case no_graph:
86       break;
87     }
88
89 #if 0
90   /* FIXME Should this be printed?  It makes the graph significantly larger.  */
91
92   /* Print the live-at-start register list.  */
93   fputc ('\n', fp);
94   EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
95     {
96       fprintf (fp, " %d", i);
97       if (i < FIRST_PSEUDO_REGISTER)
98         fprintf (fp, " [%s]", reg_names[i]);
99     }
100 #endif
101
102   switch (graph_dump_format)
103     {
104     case vcg:
105       fputs ("\"\n\n", fp);
106       break;
107     case no_graph:
108       break;
109     }
110 }
111
112 static void
113 node_data (FILE *fp, rtx tmp_rtx)
114 {
115   if (PREV_INSN (tmp_rtx) == 0)
116     {
117       /* This is the first instruction.  Add an edge from the starting
118          block.  */
119       switch (graph_dump_format)
120         {
121         case vcg:
122           fprintf (fp, "\
123 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
124                    current_function_name (),
125                    current_function_name (), XINT (tmp_rtx, 0));
126           break;
127         case no_graph:
128           break;
129         }
130     }
131
132   switch (graph_dump_format)
133     {
134     case vcg:
135       fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
136 label: \"%s %d\n",
137                current_function_name (), XINT (tmp_rtx, 0),
138                NOTE_P (tmp_rtx) ? "lightgrey"
139                : NONJUMP_INSN_P (tmp_rtx) ? "green"
140                : JUMP_P (tmp_rtx) ? "darkgreen"
141                : CALL_P (tmp_rtx) ? "darkgreen"
142                : LABEL_P (tmp_rtx) ?  "\
143 darkgrey\n  shape: ellipse" : "white",
144                GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
145       break;
146     case no_graph:
147       break;
148     }
149
150   /* Print the RTL.  */
151   if (NOTE_P (tmp_rtx))
152     {
153       const char *name;
154       name =  GET_NOTE_INSN_NAME (NOTE_KIND (tmp_rtx));
155       fprintf (fp, " %s", name);
156     }
157   else if (INSN_P (tmp_rtx))
158     print_rtl_single (fp, PATTERN (tmp_rtx));
159   else
160     print_rtl_single (fp, tmp_rtx);
161
162   switch (graph_dump_format)
163     {
164     case vcg:
165       fputs ("\"\n}\n", fp);
166       break;
167     case no_graph:
168       break;
169     }
170 }
171
172 static void
173 draw_edge (FILE *fp, int from, int to, int bb_edge, int color_class)
174 {
175   const char * color;
176   switch (graph_dump_format)
177     {
178     case vcg:
179       color = "";
180       if (color_class == 2)
181         color = "color: red ";
182       else if (bb_edge)
183         color = "color: blue ";
184       else if (color_class == 3)
185         color = "color: green ";
186       fprintf (fp,
187                "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
188                current_function_name (), from,
189                current_function_name (), to, color);
190       if (color_class)
191         fprintf (fp, "class: %d ", color_class);
192       fputs ("}\n", fp);
193       break;
194     case no_graph:
195       break;
196     }
197 }
198
199 static void
200 end_bb (FILE *fp)
201 {
202   switch (graph_dump_format)
203     {
204     case vcg:
205       /* Check if we are inside of a building block.  */
206       if (inbb != 0)
207         {
208           fputs ("}\n", fp);
209           inbb = 0; /* Now we are outside of a building block.  */
210         }
211       break;
212     case no_graph:
213       break;
214     }
215 }
216
217 static void
218 end_fct (FILE *fp)
219 {
220   switch (graph_dump_format)
221     {
222     case vcg:
223       fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
224                current_function_name ());
225       break;
226     case no_graph:
227       break;
228     }
229 }
230 \f
231 /* Like print_rtl, but also print out live information for the start of each
232    basic block.  */
233 void
234 print_rtl_graph_with_bb (const char *base, rtx rtx_first)
235 {
236   rtx tmp_rtx;
237   size_t namelen = strlen (base);
238   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
239   char *buf = XALLOCAVEC (char, namelen + extlen);
240   FILE *fp;
241
242   if (basic_block_info == NULL)
243     return;
244
245   memcpy (buf, base, namelen);
246   memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
247
248   fp = fopen (buf, "a");
249   if (fp == NULL)
250     return;
251
252   if (rtx_first == 0)
253     fprintf (fp, "(nil)\n");
254   else
255     {
256       enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
257       int max_uid = get_max_uid ();
258       int *start = XNEWVEC (int, max_uid);
259       int *end = XNEWVEC (int, max_uid);
260       enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
261       basic_block bb;
262       int i;
263
264       for (i = 0; i < max_uid; ++i)
265         {
266           start[i] = end[i] = -1;
267           in_bb_p[i] = NOT_IN_BB;
268         }
269
270       FOR_EACH_BB_REVERSE (bb)
271         {
272           rtx x;
273           start[INSN_UID (BB_HEAD (bb))] = bb->index;
274           end[INSN_UID (BB_END (bb))] = bb->index;
275           for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
276             {
277               in_bb_p[INSN_UID (x)]
278                 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
279                  ? IN_ONE_BB : IN_MULTIPLE_BB;
280               if (x == BB_END (bb))
281                 break;
282             }
283         }
284
285       /* Tell print-rtl that we want graph output.  */
286       dump_for_graph = 1;
287
288       /* Start new function.  */
289       start_fct (fp);
290
291       for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
292            tmp_rtx = NEXT_INSN (tmp_rtx))
293         {
294           int edge_printed = 0;
295           rtx next_insn;
296
297           if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
298             {
299               if (BARRIER_P (tmp_rtx))
300                 continue;
301               if (NOTE_P (tmp_rtx)
302                   && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
303                 continue;
304             }
305
306           if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
307             {
308               /* We start a subgraph for each basic block.  */
309               start_bb (fp, i);
310
311               if (i == 0)
312                 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
313             }
314
315           /* Print the data for this node.  */
316           node_data (fp, tmp_rtx);
317           next_insn = next_nonnote_insn (tmp_rtx);
318
319           if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
320             {
321               edge e;
322               edge_iterator ei;
323
324               bb = BASIC_BLOCK (i);
325
326               /* End of the basic block.  */
327               end_bb (fp);
328
329               /* Now specify the edges to all the successors of this
330                  basic block.  */
331               FOR_EACH_EDGE (e, ei, bb->succs)
332                 {
333                   if (e->dest != EXIT_BLOCK_PTR)
334                     {
335                       rtx block_head = BB_HEAD (e->dest);
336
337                       draw_edge (fp, INSN_UID (tmp_rtx),
338                                  INSN_UID (block_head),
339                                  next_insn != block_head,
340                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
341
342                       if (block_head == next_insn)
343                         edge_printed = 1;
344                     }
345                   else
346                     {
347                       draw_edge (fp, INSN_UID (tmp_rtx), 999999,
348                                  next_insn != 0,
349                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
350
351                       if (next_insn == 0)
352                         edge_printed = 1;
353                     }
354                 }
355             }
356
357           if (!edge_printed)
358             {
359               /* Don't print edges to barriers.  */
360               if (next_insn == 0
361                   || !BARRIER_P (next_insn))
362                 draw_edge (fp, XINT (tmp_rtx, 0),
363                            next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
364               else
365                 {
366                   /* We draw the remaining edges in class 3.  We have
367                      to skip over the barrier since these nodes are
368                      not printed at all.  */
369                   do
370                     next_insn = NEXT_INSN (next_insn);
371                   while (next_insn
372                          && (NOTE_P (next_insn)
373                              || BARRIER_P (next_insn)));
374
375                   draw_edge (fp, XINT (tmp_rtx, 0),
376                              next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
377                 }
378             }
379         }
380
381       dump_for_graph = 0;
382
383       end_fct (fp);
384
385       /* Clean up.  */
386       free (start);
387       free (end);
388       free (in_bb_p);
389     }
390
391   fclose (fp);
392 }
393
394
395 /* Similar as clean_dump_file, but this time for graph output files.  */
396
397 void
398 clean_graph_dump_file (const char *base)
399 {
400   size_t namelen = strlen (base);
401   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
402   char *buf = XALLOCAVEC (char, namelen + extlen);
403   FILE *fp;
404
405   memcpy (buf, base, namelen);
406   memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
407
408   fp = fopen (buf, "w");
409
410   if (fp == NULL)
411     fatal_error ("can%'t open %s: %m", buf);
412
413   gcc_assert (graph_dump_format == vcg);
414   fputs ("graph: {\nport_sharing: no\n", fp);
415
416   fclose (fp);
417 }
418
419
420 /* Do final work on the graph output file.  */
421 void
422 finish_graph_dump_file (const char *base)
423 {
424   size_t namelen = strlen (base);
425   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
426   char *buf = XALLOCAVEC (char, namelen + extlen);
427   FILE *fp;
428
429   memcpy (buf, base, namelen);
430   memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
431
432   fp = fopen (buf, "a");
433   if (fp != NULL)
434     {
435       gcc_assert (graph_dump_format == vcg);
436       fputs ("}\n", fp);
437       fclose (fp);
438     }
439 }