OSDN Git Service

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