graph.c revision 90075
1/* Output routines for graphical representation.
2   Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
3   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-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
34static const char *const graph_ext[] =
35{
36  /* no_graph */ "",
37  /* vcg */      ".vcg",
38};
39
40static void start_fct PARAMS ((FILE *));
41static void start_bb PARAMS ((FILE *, int));
42static void node_data PARAMS ((FILE *, rtx));
43static void draw_edge PARAMS ((FILE *, int, int, int, int));
44static void end_fct PARAMS ((FILE *));
45static void end_bb PARAMS ((FILE *));
46
47/* Output text for new basic block.  */
48static void
49start_fct (fp)
50     FILE *fp;
51{
52
53  switch (graph_dump_format)
54    {
55    case vcg:
56      fprintf (fp, "\
57graph: { 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
65static void
66start_bb (fp, bb)
67     FILE *fp;
68     int bb;
69{
70  switch (graph_dump_format)
71    {
72    case vcg:
73      fprintf (fp, "\
74graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
75label: \"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
106static void
107node_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, "\
120edge: { 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  \
133label: \"%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 ?  "\
140darkgrey\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      const char *name = "";
151      if (NOTE_LINE_NUMBER (tmp_rtx) < 0)
152	name =  GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx));
153      fprintf (fp, " %s", name);
154    }
155  else if (INSN_P (tmp_rtx))
156    print_rtl_single (fp, PATTERN (tmp_rtx));
157  else
158    print_rtl_single (fp, tmp_rtx);
159
160  switch (graph_dump_format)
161    {
162    case vcg:
163      fputs ("\"\n}\n", fp);
164      break;
165    case no_graph:
166      break;
167    }
168}
169
170static void
171draw_edge (fp, from, to, bb_edge, class)
172     FILE *fp;
173     int from;
174     int to;
175     int bb_edge;
176     int class;
177{
178  const char * color;
179  switch (graph_dump_format)
180    {
181    case vcg:
182      color = "";
183      if (class == 2)
184	color = "color: red ";
185      else if (bb_edge)
186	color = "color: blue ";
187      else if (class == 3)
188	color = "color: green ";
189      fprintf (fp,
190	       "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
191	       current_function_name, from,
192	       current_function_name, to, color);
193      if (class)
194	fprintf (fp, "class: %d ", class);
195      fputs ("}\n", fp);
196      break;
197    case no_graph:
198      break;
199    }
200}
201
202static void
203end_bb (fp)
204     FILE *fp;
205{
206  switch (graph_dump_format)
207    {
208    case vcg:
209      fputs ("}\n", fp);
210      break;
211    case no_graph:
212      break;
213    }
214}
215
216static void
217end_fct (fp)
218     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
231/* Like print_rtl, but also print out live information for the start of each
232   basic block.  */
233void
234print_rtl_graph_with_bb (base, suffix, rtx_first)
235     const char *base;
236     const char *suffix;
237     rtx rtx_first;
238{
239  rtx tmp_rtx;
240  size_t namelen = strlen (base);
241  size_t suffixlen = strlen (suffix);
242  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
243  char *buf = (char *) alloca (namelen + suffixlen + extlen);
244  FILE *fp;
245
246  if (basic_block_info == NULL)
247    return;
248
249  memcpy (buf, base, namelen);
250  memcpy (buf + namelen, suffix, suffixlen);
251  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
252
253  fp = fopen (buf, "a");
254  if (fp == NULL)
255    return;
256
257  if (rtx_first == 0)
258    fprintf (fp, "(nil)\n");
259  else
260    {
261      int i;
262      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
263      int max_uid = get_max_uid ();
264      int *start = (int *) xmalloc (max_uid * sizeof (int));
265      int *end = (int *) xmalloc (max_uid * sizeof (int));
266      enum bb_state *in_bb_p = (enum bb_state *)
267	xmalloc (max_uid * sizeof (enum bb_state));
268      basic_block bb;
269
270      for (i = 0; i < max_uid; ++i)
271	{
272	  start[i] = end[i] = -1;
273	  in_bb_p[i] = NOT_IN_BB;
274	}
275
276      for (i = n_basic_blocks - 1; i >= 0; --i)
277	{
278	  rtx x;
279	  bb = BASIC_BLOCK (i);
280	  start[INSN_UID (bb->head)] = i;
281	  end[INSN_UID (bb->end)] = i;
282	  for (x = bb->head; x != NULL_RTX; x = NEXT_INSN (x))
283	    {
284	      in_bb_p[INSN_UID (x)]
285		= (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
286		 ? IN_ONE_BB : IN_MULTIPLE_BB;
287	      if (x == bb->end)
288		break;
289	    }
290	}
291
292      /* Tell print-rtl that we want graph output.  */
293      dump_for_graph = 1;
294
295      /* Start new function.  */
296      start_fct (fp);
297
298      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
299	   tmp_rtx = NEXT_INSN (tmp_rtx))
300	{
301	  int edge_printed = 0;
302	  rtx next_insn;
303
304	  if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
305	    {
306	      if (GET_CODE (tmp_rtx) == BARRIER)
307		continue;
308	      if (GET_CODE (tmp_rtx) == NOTE
309		  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
310		continue;
311	    }
312
313	  if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
314	    {
315	      /* We start a subgraph for each basic block.  */
316	      start_bb (fp, i);
317
318	      if (i == 0)
319		draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
320	    }
321
322	  /* Print the data for this node.  */
323	  node_data (fp, tmp_rtx);
324	  next_insn = next_nonnote_insn (tmp_rtx);
325
326	  if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
327	    {
328	      edge e;
329
330	      bb = BASIC_BLOCK (i);
331
332	      /* End of the basic block.  */
333	      end_bb (fp);
334
335	      /* Now specify the edges to all the successors of this
336		 basic block.  */
337	      for (e = bb->succ; e ; e = e->succ_next)
338		{
339		  if (e->dest != EXIT_BLOCK_PTR)
340		    {
341		      rtx block_head = e->dest->head;
342
343		      draw_edge (fp, INSN_UID (tmp_rtx),
344				 INSN_UID (block_head),
345				 next_insn != block_head,
346				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
347
348		      if (block_head == next_insn)
349			edge_printed = 1;
350		    }
351		  else
352		    {
353		      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
354				 next_insn != 0,
355				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
356
357		      if (next_insn == 0)
358			edge_printed = 1;
359		    }
360		}
361	    }
362
363	  if (!edge_printed)
364	    {
365	      /* Don't print edges to barriers.  */
366	      if (next_insn == 0
367		  || GET_CODE (next_insn) != BARRIER)
368		draw_edge (fp, XINT (tmp_rtx, 0),
369			   next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
370	      else
371		{
372		  /* We draw the remaining edges in class 3.  We have
373		     to skip over the barrier since these nodes are
374		     not printed at all.  */
375		  do
376		    next_insn = NEXT_INSN (next_insn);
377		  while (next_insn
378			 && (GET_CODE (next_insn) == NOTE
379			     || GET_CODE (next_insn) == BARRIER));
380
381		  draw_edge (fp, XINT (tmp_rtx, 0),
382			     next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
383		}
384	    }
385	}
386
387      dump_for_graph = 0;
388
389      end_fct (fp);
390
391      /* Clean up.  */
392      free (start);
393      free (end);
394      free (in_bb_p);
395    }
396
397  fclose (fp);
398}
399
400
401/* Similar as clean_dump_file, but this time for graph output files.  */
402
403void
404clean_graph_dump_file (base, suffix)
405     const char *base;
406     const char *suffix;
407{
408  size_t namelen = strlen (base);
409  size_t suffixlen = strlen (suffix);
410  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
411  char *buf = (char *) alloca (namelen + extlen + suffixlen);
412  FILE *fp;
413
414  memcpy (buf, base, namelen);
415  memcpy (buf + namelen, suffix, suffixlen);
416  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
417
418  fp = fopen (buf, "w");
419
420  if (fp == NULL)
421    fatal_io_error ("can't open %s", buf);
422
423  switch (graph_dump_format)
424    {
425    case vcg:
426      fputs ("graph: {\nport_sharing: no\n", fp);
427      break;
428    case no_graph:
429      abort ();
430    }
431
432  fclose (fp);
433}
434
435
436/* Do final work on the graph output file.  */
437void
438finish_graph_dump_file (base, suffix)
439     const char *base;
440     const char *suffix;
441{
442  size_t namelen = strlen (base);
443  size_t suffixlen = strlen (suffix);
444  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
445  char *buf = (char *) alloca (namelen + suffixlen + extlen);
446  FILE *fp;
447
448  memcpy (buf, base, namelen);
449  memcpy (buf + namelen, suffix, suffixlen);
450  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
451
452  fp = fopen (buf, "a");
453  if (fp != NULL)
454    {
455      switch (graph_dump_format)
456	{
457	case vcg:
458	  fputs ("}\n", fp);
459	  break;
460	case no_graph:
461	  abort ();
462	}
463
464      fclose (fp);
465    }
466}
467