Buglet in last commit, the first argument of bpf_ptap is the actual bpf_if.
[dragonfly.git] / contrib / 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 void
98 node_data (fp, tmp_rtx)
99      FILE *fp;
100      rtx tmp_rtx;
101 {
102
103   if (PREV_INSN (tmp_rtx) == 0)
104     {
105       /* This is the first instruction.  Add an edge from the starting
106          block.  */
107       switch (graph_dump_format)
108         {
109         case vcg:
110           fprintf (fp, "\
111 edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
112                    current_function_name,
113                    current_function_name, XINT (tmp_rtx, 0));
114           break;
115         case no_graph:
116           break;
117         }
118     }
119
120   switch (graph_dump_format)
121     {
122     case vcg:
123       fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
124 label: \"%s %d\n",
125                current_function_name, XINT (tmp_rtx, 0),
126                GET_CODE (tmp_rtx) == NOTE ? "lightgrey"
127                : GET_CODE (tmp_rtx) == INSN ? "green"
128                : GET_CODE (tmp_rtx) == JUMP_INSN ? "darkgreen"
129                : GET_CODE (tmp_rtx) == CALL_INSN ? "darkgreen"
130                : GET_CODE (tmp_rtx) == CODE_LABEL ?  "\
131 darkgrey\n  shape: ellipse" : "white",
132                GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
133       break;
134     case no_graph:
135       break;
136     }
137
138   /* Print the RTL.  */
139   if (GET_CODE (tmp_rtx) == NOTE)
140     {
141       static const char *note_names[] =
142       {
143         NULL,
144         "deleted",
145         "block_beg",
146         "block_end",
147         "loop_beg",
148         "loop_end",
149         "function_end",
150         "setjmp",
151         "loop_cont",
152         "loop_vtop",
153         "prologue_end",
154         "epilogue_beg",
155         "deleted_label",
156         "function_beg",
157         "eh_region_beg",
158         "eh_region_end",
159         "repeated_line_number",
160         "range_start",
161         "range_end",
162         "live",
163         "basic_block"
164       };
165
166       fprintf (fp, " %s",
167                XINT (tmp_rtx, 4) < 0 ? note_names[-XINT (tmp_rtx, 4)] : "");
168     }
169   else if (GET_RTX_CLASS (GET_CODE (tmp_rtx)) == 'i')
170     print_rtl_single (fp, PATTERN (tmp_rtx));
171   else
172     print_rtl_single (fp, tmp_rtx);
173
174   switch (graph_dump_format)
175     {
176     case vcg:
177       fputs ("\"\n}\n", fp);
178       break;
179     case no_graph:
180       break;
181     }
182 }
183
184 static void
185 draw_edge (fp, from, to, bb_edge, class)
186      FILE *fp;
187      int from;
188      int to;
189      int bb_edge;
190      int class;
191 {
192   char * color;
193   switch (graph_dump_format)
194     {
195     case vcg:
196       color = "";
197       if (class == 2)
198         color = "color: red ";
199       else if (bb_edge)
200         color = "color: blue ";
201       else if (class == 3)
202         color = "color: green ";
203       fprintf (fp,
204                "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
205                current_function_name, from,
206                current_function_name, to, color);
207       if (class)
208         fprintf (fp, "class: %d ", class);
209       fputs ("}\n", fp);
210       break;
211     case no_graph:
212       break;
213     }
214 }
215
216 static void
217 end_bb (fp, bb)
218      FILE *fp;
219      int bb ATTRIBUTE_UNUSED;
220 {
221   switch (graph_dump_format)
222     {
223     case vcg:
224       fputs ("}\n", fp);
225       break;
226     case no_graph:
227       break;
228     }
229 }
230
231 static void
232 end_fct (fp)
233      FILE *fp;
234 {
235   switch (graph_dump_format)
236     {
237     case vcg:
238       fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
239                current_function_name);
240       break;
241     case no_graph:
242       break;
243     }
244 }
245 \f
246 /* Like print_rtl, but also print out live information for the start of each
247    basic block.  */
248 void
249 print_rtl_graph_with_bb (base, suffix, rtx_first)
250      const char *base;
251      const char *suffix;
252      rtx rtx_first;
253 {
254   register rtx tmp_rtx;
255   size_t namelen = strlen (base);
256   size_t suffixlen = strlen (suffix);
257   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
258   char *buf = (char *) alloca (namelen + suffixlen + extlen);
259   FILE *fp;
260
261   if (basic_block_info == NULL)
262     return;
263
264   memcpy (buf, base, namelen);
265   memcpy (buf + namelen, suffix, suffixlen);
266   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
267
268   fp = fopen (buf, "a");
269   if (fp == NULL)
270     return;
271
272   if (rtx_first == 0)
273     fprintf (fp, "(nil)\n");
274   else
275     {
276       int i;
277       enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
278       int max_uid = get_max_uid ();
279       int *start = (int *) alloca (max_uid * sizeof (int));
280       int *end = (int *) alloca (max_uid * sizeof (int));
281       enum bb_state *in_bb_p = (enum bb_state *)
282         alloca (max_uid * sizeof (enum bb_state));
283       basic_block bb;
284
285       for (i = 0; i < max_uid; ++i)
286         {
287           start[i] = end[i] = -1;
288           in_bb_p[i] = NOT_IN_BB;
289         }
290
291       for (i = n_basic_blocks - 1; i >= 0; --i)
292         {
293           rtx x;
294           bb = BASIC_BLOCK (i);
295           start[INSN_UID (bb->head)] = i;
296           end[INSN_UID (bb->end)] = i;
297           for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
298             {
299               in_bb_p[INSN_UID (x)]
300                 = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
301                  ? IN_ONE_BB : IN_MULTIPLE_BB;
302               if (x == bb->end)
303                 break;
304             }
305         }
306
307       /* Tell print-rtl that we want graph output.  */
308       dump_for_graph = 1;
309
310       /* Start new function.  */
311       start_fct (fp);
312
313       for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
314            tmp_rtx = NEXT_INSN (tmp_rtx))
315         {
316           int edge_printed = 0;
317           rtx next_insn;
318
319           if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
320             {
321               if (GET_CODE (tmp_rtx) == BARRIER)
322                 continue;
323               if (GET_CODE (tmp_rtx) == NOTE
324                   && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
325                 continue;
326             }
327
328           if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
329             {
330               /* We start a subgraph for each basic block.  */
331               start_bb (fp, i);
332
333               if (i == 0)
334                 draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
335             }
336
337           /* Print the data for this node.  */
338           node_data (fp, tmp_rtx);
339           next_insn = next_nonnote_insn (tmp_rtx);
340
341           if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
342             {
343               edge e;
344
345               bb = BASIC_BLOCK (i);
346
347               /* End of the basic block.  */
348               end_bb (fp, bb);
349
350               /* Now specify the edges to all the successors of this
351                  basic block.  */
352               for (e = bb->succ; e ; e = e->succ_next)
353                 {
354                   if (e->dest != EXIT_BLOCK_PTR)
355                     {
356                       rtx block_head = e->dest->head;
357
358                       draw_edge (fp, INSN_UID (tmp_rtx),
359                                  INSN_UID (block_head),
360                                  next_insn != block_head,
361                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
362
363                       if (block_head == next_insn)
364                         edge_printed = 1;
365                     }
366                   else
367                     {
368                       draw_edge (fp, INSN_UID (tmp_rtx), 999999,
369                                  next_insn != 0,
370                                  (e->flags & EDGE_ABNORMAL ? 2 : 0));
371
372                       if (next_insn == 0)
373                         edge_printed = 1;
374                     }
375                 }
376             }
377
378           if (!edge_printed)
379             {
380               /* Don't print edges to barriers.  */
381               if (next_insn == 0
382                   || GET_CODE (next_insn) != BARRIER)
383                 draw_edge (fp, XINT (tmp_rtx, 0),
384                            next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
385               else
386                 {
387                   /* We draw the remaining edges in class 3.  We have
388                      to skip over the barrier since these nodes are
389                      not printed at all.  */
390                   do
391                     next_insn = NEXT_INSN (next_insn);
392                   while (next_insn
393                          && (GET_CODE (next_insn) == NOTE
394                              || GET_CODE (next_insn) == BARRIER));
395
396                   draw_edge (fp, XINT (tmp_rtx, 0),
397                              next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
398                 }
399             }
400         }
401
402       dump_for_graph = 0;
403
404       end_fct (fp);
405     }
406
407   fclose (fp);
408 }
409
410
411 /* Similar as clean_dump_file, but this time for graph output files.  */
412 void
413 clean_graph_dump_file (base, suffix)
414      const char *base;
415      const char *suffix;
416 {
417   size_t namelen = strlen (base);
418   size_t suffixlen = strlen (suffix);
419   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
420   char *buf = (char *) alloca (namelen + extlen + suffixlen);
421   FILE *fp;
422
423   memcpy (buf, base, namelen);
424   memcpy (buf + namelen, suffix, suffixlen);
425   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
426
427   fp = fopen (buf, "w");
428
429   if (fp == NULL)
430     pfatal_with_name (buf);
431
432   switch (graph_dump_format)
433     {
434     case vcg:
435       fputs ("graph: {\nport_sharing: no\n", fp);
436       break;
437     case no_graph:
438       abort ();
439     }
440
441   fclose (fp);
442 }
443
444
445 /* Do final work on the graph output file.  */
446 void
447 finish_graph_dump_file (base, suffix)
448      const char *base;
449      const char *suffix;
450 {
451   size_t namelen = strlen (base);
452   size_t suffixlen = strlen (suffix);
453   size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
454   char *buf = (char *) alloca (namelen + suffixlen + extlen);
455   FILE *fp;
456
457   memcpy (buf, base, namelen);
458   memcpy (buf + namelen, suffix, suffixlen);
459   memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
460
461   fp = fopen (buf, "a");
462   if (fp != NULL)
463     {
464       switch (graph_dump_format)
465         {
466         case vcg:
467           fputs ("}\n", fp);
468           break;
469         case no_graph:
470           abort ();
471         }
472
473       fclose (fp);
474     }
475 }