OSDN Git Service

Flow rewrite to use basic block structures and edge lists.
[pf3gnuchains/gcc-fork.git] / gcc / graph.c
1 /* Output routines for graphical representation.
2    Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4
5    This file is part of GNU CC.
6
7    GNU CC is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11
12    GNU CC is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GNU CC; see the file COPYING.  If not, write to
19    the Free Software Foundation, 59 Temple Place - Suite 330,
20    Boston, MA 02111-1307, USA.  */
21
22 #include <config.h>
23 #include "system.h"
24
25 #include "rtl.h"
26 #include "flags.h"
27 #include "output.h"
28 #include "hard-reg-set.h"
29 #include "basic-block.h"
30 #include "toplev.h"
31
32 static const char *graph_ext[] =
33 {
34   /* no_graph */ "",
35   /* vcg */      ".vcg",
36 };
37
38 /* Output text for new basic block.  */
39 static void
40 start_fct (fp)
41      FILE *fp;
42 {
43
44   switch (graph_dump_format)
45     {
46     case vcg:
47       fprintf (fp, "\
48 graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
49                current_function_name, current_function_name);
50       break;
51     case no_graph:
52       break;
53     }
54 }
55
56 static void
57 start_bb (fp, bb)
58      FILE *fp;
59      int bb;
60 {
61   switch (graph_dump_format)
62     {
63     case vcg:
64       fprintf (fp, "\
65 graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
66 label: \"basic block %d",
67                current_function_name, bb, bb);
68       break;
69     case no_graph:
70       break;
71     }
72
73 #if 0
74   /* FIXME Should this be printed?  It makes the graph significantly larger. */
75
76   /* Print the live-at-start register list.  */
77   fputc ('\n', fp);
78   EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i,
79                              {
80                                fprintf (fp, " %d", i);
81                                if (i < FIRST_PSEUDO_REGISTER)
82                                  fprintf (fp, " [%s]",
83                                           reg_names[i]);
84                              });
85 #endif
86
87   switch (graph_dump_format)
88     {
89     case vcg:
90       fputs ("\"\n\n", fp);
91       break;
92     case no_graph:
93       break;
94     }
95 }
96
97 static int
98 node_data (fp, tmp_rtx)
99      FILE *fp;
100      rtx tmp_rtx;
101 {
102   int result;
103
104   if (PREV_INSN (tmp_rtx) == 0)
105     {
106       /* This is the first instruction.  Add an edge from the starting
107          block.  */
108       switch (graph_dump_format)
109         {
110         case vcg:
111           fprintf (fp, "\
112 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
113                    current_function_name,
114                    current_function_name, XINT (tmp_rtx, 0));
115           break;
116         case no_graph:
117           break;
118         }
119     }
120
121   switch (graph_dump_format)
122     {
123     case vcg:
124       fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
125 label: \"%s %d\n",
126                current_function_name, XINT (tmp_rtx, 0),
127                GET_CODE (tmp_rtx) == NOTE ? "lightgrey"
128                : GET_CODE (tmp_rtx) == INSN ? "green"
129                : GET_CODE (tmp_rtx) == JUMP_INSN ? "darkgreen"
130                : GET_CODE (tmp_rtx) == CALL_INSN ? "darkgreen"
131                : GET_CODE (tmp_rtx) == CODE_LABEL ?  "\
132 darkgrey\n  shape: ellipse" : "white",
133                GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
134       break;
135     case no_graph:
136       break;
137     }
138
139   /* Print the RTL.  */
140   if (GET_CODE (tmp_rtx) == NOTE)
141     {
142       static const char *note_names[] =
143       {
144         NULL,
145         "deleted",
146         "block_beg",
147         "block_end",
148         "loop_beg",
149         "loop_end",
150         "function_end",
151         "setjmp",
152         "loop_cont",
153         "loop_vtop",
154         "prologue_end",
155         "epilogue_beg",
156         "deleted_label",
157         "function_beg",
158         "eh_region_beg",
159         "eh_region_end",
160         "repeated_line_number",
161         "range_start",
162         "range_end",
163         "live",
164         "basic_block"
165       };
166
167       fprintf (fp, " %s",
168                XINT (tmp_rtx, 4) < 0 ? note_names[-XINT (tmp_rtx, 4)] : "");
169     }
170   else if (GET_RTX_CLASS (GET_CODE (tmp_rtx)) == 'i')
171     result = print_rtl_single (fp, PATTERN (tmp_rtx));
172   else
173     result = print_rtl_single (fp, tmp_rtx);
174
175   switch (graph_dump_format)
176     {
177     case vcg:
178       fputs ("\"\n}\n", fp);
179       break;
180     case no_graph:
181       break;
182     }
183
184   return result;
185 }
186
187 static void
188 draw_edge (fp, from, to, bb_edge, class)
189      FILE *fp;
190      int from;
191      int to;
192      int bb_edge;
193      int class;
194 {
195   char * color;
196   switch (graph_dump_format)
197     {
198     case vcg:
199       color = "";
200       if (class == 2)
201         color = "color: red ";
202       else if (bb_edge)
203         color = "color: blue ";
204       else if (class == 3)
205         color = "color: green ";
206       fprintf (fp,
207                "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
208                current_function_name, from,
209                current_function_name, to, color);
210       if (class)
211         fprintf (fp, "class: %d ", class);
212       fputs ("}\n", fp);
213       break;
214     case no_graph:
215       break;
216     }
217 }
218
219 static void
220 end_bb (fp, bb)
221      FILE *fp;
222      int bb ATTRIBUTE_UNUSED;
223 {
224   switch (graph_dump_format)
225     {
226     case vcg:
227       fputs ("}\n", fp);
228       break;
229     case no_graph:
230       break;
231     }
232 }
233
234 static void
235 end_fct (fp)
236      FILE *fp;
237 {
238   switch (graph_dump_format)
239     {
240     case vcg:
241       fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
242                current_function_name);
243       break;
244     case no_graph:
245       break;
246     }
247 }
248 \f
249 /* Like print_rtl, but also print out live information for the start of each
250    basic block.  */
251 void
252 print_rtl_graph_with_bb (base, suffix, rtx_first)
253      const char *base;
254      const char *suffix;
255      rtx rtx_first;
256 {
257   register rtx tmp_rtx;
258   size_t namelen = strlen (base);
259   size_t suffixlen = strlen (suffix);
260   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
261   char *buf = (char *) alloca (namelen + suffixlen + extlen);
262   FILE *fp;
263
264   if (basic_block_info == NULL)
265     return;
266
267   memcpy (buf, base, namelen);
268   memcpy (buf + namelen, suffix, suffixlen);
269   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
270
271   fp = fopen (buf, "a");
272   if (fp == NULL)
273     return;
274
275   if (rtx_first == 0)
276     fprintf (fp, "(nil)\n");
277   else
278     {
279       int i;
280       enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
281       int max_uid = get_max_uid ();
282       int *start = (int *) alloca (max_uid * sizeof (int));
283       int *end = (int *) alloca (max_uid * sizeof (int));
284       enum bb_state *in_bb_p = (enum bb_state *)
285         alloca (max_uid * sizeof (enum bb_state));
286       basic_block bb;
287
288       for (i = 0; i < max_uid; ++i)
289         {
290           start[i] = end[i] = -1;
291           in_bb_p[i] = NOT_IN_BB;
292         }
293
294       for (i = n_basic_blocks - 1; i >= 0; --i)
295         {
296           rtx x;
297           bb = BASIC_BLOCK (i);
298           start[INSN_UID (bb->head)] = i;
299           end[INSN_UID (bb->end)] = i;
300           for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
301             {
302               in_bb_p[INSN_UID (x)]
303                 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
304                  ? IN_ONE_BB : IN_MULTIPLE_BB;
305               if (x == bb->end)
306                 break;
307             }
308         }
309
310       /* Tell print-rtl that we want graph output.  */
311       dump_for_graph = 1;
312
313       /* Start new function.  */
314       start_fct (fp);
315
316       for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
317            tmp_rtx = NEXT_INSN (tmp_rtx))
318         {
319           int did_output;
320           int edge_printed = 0;
321           rtx next_insn;
322
323           if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
324             {
325               if (GET_CODE (tmp_rtx) == BARRIER)
326                 continue;
327               if (GET_CODE (tmp_rtx) == NOTE
328                   && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
329                 continue;
330             }
331
332           if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
333             {
334               /* We start a subgraph for each basic block.  */
335               start_bb (fp, i);
336
337               if (i == 0)
338                 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
339             }
340
341           /* Print the data for this node.  */
342           did_output = node_data (fp, tmp_rtx);
343           next_insn = next_nonnote_insn (tmp_rtx);
344
345           if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
346             {
347               edge e;
348
349               bb = BASIC_BLOCK (i);
350
351               /* End of the basic block.  */
352               end_bb (fp, bb);
353
354               /* Now specify the edges to all the successors of this
355                  basic block.  */
356               for (e = bb->succ; e ; e = e->succ_next)
357                 {
358                   if (e->dest != EXIT_BLOCK_PTR)
359                     {
360                       rtx block_head = e->dest->head;
361
362                       draw_edge (fp, INSN_UID (tmp_rtx),
363                                  INSN_UID (block_head),
364                                  next_insn != block_head,
365                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
366
367                       if (block_head == next_insn)
368                         edge_printed = 1;
369                     }
370                   else
371                     {
372                       draw_edge (fp, INSN_UID (tmp_rtx), 999999,
373                                  next_insn != 0,
374                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
375
376                       if (next_insn == 0)
377                         edge_printed = 1;
378                     }
379                 }
380             }
381
382           if (!edge_printed)
383             {
384               /* Don't print edges to barriers.  */
385               if (next_insn == 0
386                   || GET_CODE (next_insn) != BARRIER)
387                 draw_edge (fp, XINT (tmp_rtx, 0),
388                            next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
389               else
390                 {
391                   /* We draw the remaining edges in class 3.  We have
392                      to skip over the barrier since these nodes are
393                      not printed at all.  */
394                   do
395                     next_insn = NEXT_INSN (next_insn);
396                   while (next_insn
397                          && (GET_CODE (next_insn) == NOTE
398                              || GET_CODE (next_insn) == BARRIER));
399
400                   draw_edge (fp, XINT (tmp_rtx, 0),
401                              next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
402                 }
403             }
404         }
405
406       dump_for_graph = 0;
407
408       end_fct (fp);
409     }
410
411   fclose (fp);
412 }
413
414
415 /* Similar as clean_dump_file, but this time for graph output files.  */
416 void
417 clean_graph_dump_file (base, suffix)
418      const char *base;
419      const char *suffix;
420 {
421   size_t namelen = strlen (base);
422   size_t suffixlen = strlen (suffix);
423   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
424   char *buf = (char *) alloca (namelen + extlen + suffixlen);
425   FILE *fp;
426
427   memcpy (buf, base, namelen);
428   memcpy (buf + namelen, suffix, suffixlen);
429   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
430
431   fp = fopen (buf, "w");
432
433   if (fp == NULL)
434     pfatal_with_name (buf);
435
436   switch (graph_dump_format)
437     {
438     case vcg:
439       fputs ("graph: {\nport_sharing: no\n", fp);
440       break;
441     case no_graph:
442       abort ();
443     }
444
445   fclose (fp);
446 }
447
448
449 /* Do final work on the graph output file.  */
450 void
451 finish_graph_dump_file (base, suffix)
452      const char *base;
453      const char *suffix;
454 {
455   size_t namelen = strlen (base);
456   size_t suffixlen = strlen (suffix);
457   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
458   char *buf = (char *) alloca (namelen + suffixlen + extlen);
459   FILE *fp;
460
461   memcpy (buf, base, namelen);
462   memcpy (buf + namelen, suffix, suffixlen);
463   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
464
465   fp = fopen (buf, "a");
466   if (fp != NULL)
467     {
468       switch (graph_dump_format)
469         {
470         case vcg:
471           fputs ("}\n", fp);
472           break;
473         case no_graph:
474           abort ();
475         }
476
477       fclose (fp);
478     }
479 }