152284Sobrien/* Output routines for graphical representation.
2132718Skan   Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004
3132718Skan   Free Software Foundation, Inc.
452284Sobrien   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
552284Sobrien
690075SobrienThis file is part of GCC.
752284Sobrien
890075SobrienGCC is free software; you can redistribute it and/or modify it under
990075Sobrienthe terms of the GNU General Public License as published by the Free
1090075SobrienSoftware Foundation; either version 2, or (at your option) any later
1190075Sobrienversion.
1252284Sobrien
1390075SobrienGCC is distributed in the hope that it will be useful, but WITHOUT ANY
1490075SobrienWARRANTY; without even the implied warranty of MERCHANTABILITY or
1590075SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1690075Sobrienfor more details.
1752284Sobrien
1890075SobrienYou should have received a copy of the GNU General Public License
1990075Sobrienalong with GCC; see the file COPYING.  If not, write to the Free
20169689SkanSoftware Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21169689Skan02110-1301, USA.  */
2252284Sobrien
2352284Sobrien#include <config.h>
2452284Sobrien#include "system.h"
25132718Skan#include "coretypes.h"
26132718Skan#include "tm.h"
2752284Sobrien#include "rtl.h"
2852284Sobrien#include "flags.h"
2952284Sobrien#include "output.h"
3090075Sobrien#include "function.h"
3152284Sobrien#include "hard-reg-set.h"
32169689Skan#include "obstack.h"
3352284Sobrien#include "basic-block.h"
3452284Sobrien#include "toplev.h"
3590075Sobrien#include "graph.h"
3652284Sobrien
3790075Sobrienstatic const char *const graph_ext[] =
3852284Sobrien{
3952284Sobrien  /* no_graph */ "",
4052284Sobrien  /* vcg */      ".vcg",
4152284Sobrien};
4252284Sobrien
43132718Skanstatic void start_fct (FILE *);
44132718Skanstatic void start_bb (FILE *, int);
45132718Skanstatic void node_data (FILE *, rtx);
46132718Skanstatic void draw_edge (FILE *, int, int, int, int);
47132718Skanstatic void end_fct (FILE *);
48132718Skanstatic void end_bb (FILE *);
4990075Sobrien
5052284Sobrien/* Output text for new basic block.  */
5152284Sobrienstatic void
52132718Skanstart_fct (FILE *fp)
5352284Sobrien{
5452284Sobrien  switch (graph_dump_format)
5552284Sobrien    {
5652284Sobrien    case vcg:
5752284Sobrien      fprintf (fp, "\
5852284Sobriengraph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
59132718Skan	       current_function_name (), current_function_name ());
6052284Sobrien      break;
6152284Sobrien    case no_graph:
6252284Sobrien      break;
6352284Sobrien    }
6452284Sobrien}
6552284Sobrien
6652284Sobrienstatic void
67132718Skanstart_bb (FILE *fp, int bb)
6852284Sobrien{
69169689Skan#if 0
70169689Skan  reg_set_iterator rsi;
71169689Skan#endif
72169689Skan
7352284Sobrien  switch (graph_dump_format)
7452284Sobrien    {
7552284Sobrien    case vcg:
7652284Sobrien      fprintf (fp, "\
7752284Sobriengraph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
7852284Sobrienlabel: \"basic block %d",
79132718Skan	       current_function_name (), bb, bb);
8052284Sobrien      break;
8152284Sobrien    case no_graph:
8252284Sobrien      break;
8352284Sobrien    }
8452284Sobrien
8552284Sobrien#if 0
8690075Sobrien  /* FIXME Should this be printed?  It makes the graph significantly larger.  */
8752284Sobrien
8852284Sobrien  /* Print the live-at-start register list.  */
8952284Sobrien  fputc ('\n', fp);
90169689Skan  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i, rsi)
91169689Skan    {
92169689Skan      fprintf (fp, " %d", i);
93169689Skan      if (i < FIRST_PSEUDO_REGISTER)
94169689Skan	fprintf (fp, " [%s]", reg_names[i]);
95169689Skan    }
9652284Sobrien#endif
9752284Sobrien
9852284Sobrien  switch (graph_dump_format)
9952284Sobrien    {
10052284Sobrien    case vcg:
10152284Sobrien      fputs ("\"\n\n", fp);
10252284Sobrien      break;
10352284Sobrien    case no_graph:
10452284Sobrien      break;
10552284Sobrien    }
10652284Sobrien}
10752284Sobrien
10852284Sobrienstatic void
109132718Skannode_data (FILE *fp, rtx tmp_rtx)
11052284Sobrien{
11152284Sobrien  if (PREV_INSN (tmp_rtx) == 0)
11252284Sobrien    {
11352284Sobrien      /* This is the first instruction.  Add an edge from the starting
11452284Sobrien	 block.  */
11552284Sobrien      switch (graph_dump_format)
11652284Sobrien	{
11752284Sobrien	case vcg:
11852284Sobrien	  fprintf (fp, "\
11952284Sobrienedge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
120132718Skan		   current_function_name (),
121132718Skan		   current_function_name (), XINT (tmp_rtx, 0));
12252284Sobrien	  break;
12352284Sobrien	case no_graph:
12452284Sobrien	  break;
12552284Sobrien	}
12652284Sobrien    }
12752284Sobrien
12852284Sobrien  switch (graph_dump_format)
12952284Sobrien    {
13052284Sobrien    case vcg:
13152284Sobrien      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
13252284Sobrienlabel: \"%s %d\n",
133132718Skan	       current_function_name (), XINT (tmp_rtx, 0),
134169689Skan	       NOTE_P (tmp_rtx) ? "lightgrey"
135169689Skan	       : NONJUMP_INSN_P (tmp_rtx) ? "green"
136169689Skan	       : JUMP_P (tmp_rtx) ? "darkgreen"
137169689Skan	       : CALL_P (tmp_rtx) ? "darkgreen"
138169689Skan	       : LABEL_P (tmp_rtx) ?  "\
13952284Sobriendarkgrey\n  shape: ellipse" : "white",
14052284Sobrien	       GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
14152284Sobrien      break;
14252284Sobrien    case no_graph:
14352284Sobrien      break;
14452284Sobrien    }
14552284Sobrien
14652284Sobrien  /* Print the RTL.  */
147169689Skan  if (NOTE_P (tmp_rtx))
14852284Sobrien    {
14990075Sobrien      const char *name = "";
15090075Sobrien      if (NOTE_LINE_NUMBER (tmp_rtx) < 0)
15190075Sobrien	name =  GET_NOTE_INSN_NAME (NOTE_LINE_NUMBER (tmp_rtx));
15290075Sobrien      fprintf (fp, " %s", name);
15352284Sobrien    }
15490075Sobrien  else if (INSN_P (tmp_rtx))
15552284Sobrien    print_rtl_single (fp, PATTERN (tmp_rtx));
15652284Sobrien  else
15752284Sobrien    print_rtl_single (fp, tmp_rtx);
15852284Sobrien
15952284Sobrien  switch (graph_dump_format)
16052284Sobrien    {
16152284Sobrien    case vcg:
16252284Sobrien      fputs ("\"\n}\n", fp);
16352284Sobrien      break;
16452284Sobrien    case no_graph:
16552284Sobrien      break;
16652284Sobrien    }
16752284Sobrien}
16852284Sobrien
16952284Sobrienstatic void
170132718Skandraw_edge (FILE *fp, int from, int to, int bb_edge, int class)
17152284Sobrien{
17290075Sobrien  const char * color;
17352284Sobrien  switch (graph_dump_format)
17452284Sobrien    {
17552284Sobrien    case vcg:
17652284Sobrien      color = "";
17752284Sobrien      if (class == 2)
17852284Sobrien	color = "color: red ";
17952284Sobrien      else if (bb_edge)
18052284Sobrien	color = "color: blue ";
18152284Sobrien      else if (class == 3)
18252284Sobrien	color = "color: green ";
18352284Sobrien      fprintf (fp,
18452284Sobrien	       "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
185132718Skan	       current_function_name (), from,
186132718Skan	       current_function_name (), to, color);
18752284Sobrien      if (class)
18852284Sobrien	fprintf (fp, "class: %d ", class);
18952284Sobrien      fputs ("}\n", fp);
19052284Sobrien      break;
19152284Sobrien    case no_graph:
19252284Sobrien      break;
19352284Sobrien    }
19452284Sobrien}
19552284Sobrien
19652284Sobrienstatic void
197132718Skanend_bb (FILE *fp)
19852284Sobrien{
19952284Sobrien  switch (graph_dump_format)
20052284Sobrien    {
20152284Sobrien    case vcg:
20252284Sobrien      fputs ("}\n", fp);
20352284Sobrien      break;
20452284Sobrien    case no_graph:
20552284Sobrien      break;
20652284Sobrien    }
20752284Sobrien}
20852284Sobrien
20952284Sobrienstatic void
210132718Skanend_fct (FILE *fp)
21152284Sobrien{
21252284Sobrien  switch (graph_dump_format)
21352284Sobrien    {
21452284Sobrien    case vcg:
21552284Sobrien      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
216132718Skan	       current_function_name ());
21752284Sobrien      break;
21852284Sobrien    case no_graph:
21952284Sobrien      break;
22052284Sobrien    }
22152284Sobrien}
22252284Sobrien
22352284Sobrien/* Like print_rtl, but also print out live information for the start of each
22452284Sobrien   basic block.  */
22552284Sobrienvoid
226169689Skanprint_rtl_graph_with_bb (const char *base, rtx rtx_first)
22752284Sobrien{
22890075Sobrien  rtx tmp_rtx;
22952284Sobrien  size_t namelen = strlen (base);
23052284Sobrien  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
231169689Skan  char *buf = alloca (namelen + extlen);
23252284Sobrien  FILE *fp;
23352284Sobrien
23452284Sobrien  if (basic_block_info == NULL)
23552284Sobrien    return;
23652284Sobrien
23752284Sobrien  memcpy (buf, base, namelen);
238169689Skan  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
23952284Sobrien
24052284Sobrien  fp = fopen (buf, "a");
24152284Sobrien  if (fp == NULL)
24252284Sobrien    return;
24352284Sobrien
24452284Sobrien  if (rtx_first == 0)
24552284Sobrien    fprintf (fp, "(nil)\n");
24652284Sobrien  else
24752284Sobrien    {
24852284Sobrien      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
24952284Sobrien      int max_uid = get_max_uid ();
250169689Skan      int *start = XNEWVEC (int, max_uid);
251169689Skan      int *end = XNEWVEC (int, max_uid);
252169689Skan      enum bb_state *in_bb_p = XNEWVEC (enum bb_state, max_uid);
25352284Sobrien      basic_block bb;
254117395Skan      int i;
25552284Sobrien
25652284Sobrien      for (i = 0; i < max_uid; ++i)
25752284Sobrien	{
25852284Sobrien	  start[i] = end[i] = -1;
25952284Sobrien	  in_bb_p[i] = NOT_IN_BB;
26052284Sobrien	}
26152284Sobrien
262117395Skan      FOR_EACH_BB_REVERSE (bb)
26352284Sobrien	{
26452284Sobrien	  rtx x;
265132718Skan	  start[INSN_UID (BB_HEAD (bb))] = bb->index;
266132718Skan	  end[INSN_UID (BB_END (bb))] = bb->index;
267132718Skan	  for (x = BB_HEAD (bb); x != NULL_RTX; x = NEXT_INSN (x))
26852284Sobrien	    {
26952284Sobrien	      in_bb_p[INSN_UID (x)]
27052284Sobrien		= (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
27152284Sobrien		 ? IN_ONE_BB : IN_MULTIPLE_BB;
272132718Skan	      if (x == BB_END (bb))
27352284Sobrien		break;
27452284Sobrien	    }
27552284Sobrien	}
27652284Sobrien
27752284Sobrien      /* Tell print-rtl that we want graph output.  */
27852284Sobrien      dump_for_graph = 1;
27952284Sobrien
28052284Sobrien      /* Start new function.  */
28152284Sobrien      start_fct (fp);
28252284Sobrien
28352284Sobrien      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
28452284Sobrien	   tmp_rtx = NEXT_INSN (tmp_rtx))
28552284Sobrien	{
28652284Sobrien	  int edge_printed = 0;
28752284Sobrien	  rtx next_insn;
28852284Sobrien
28952284Sobrien	  if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
29052284Sobrien	    {
291169689Skan	      if (BARRIER_P (tmp_rtx))
29252284Sobrien		continue;
293169689Skan	      if (NOTE_P (tmp_rtx)
29452284Sobrien		  && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
29552284Sobrien		continue;
29652284Sobrien	    }
29752284Sobrien
29852284Sobrien	  if ((i = start[INSN_UID (tmp_rtx)]) >= 0)
29952284Sobrien	    {
30052284Sobrien	      /* We start a subgraph for each basic block.  */
30152284Sobrien	      start_bb (fp, i);
30252284Sobrien
30352284Sobrien	      if (i == 0)
30452284Sobrien		draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
30552284Sobrien	    }
30652284Sobrien
30752284Sobrien	  /* Print the data for this node.  */
30852284Sobrien	  node_data (fp, tmp_rtx);
30952284Sobrien	  next_insn = next_nonnote_insn (tmp_rtx);
31052284Sobrien
31152284Sobrien	  if ((i = end[INSN_UID (tmp_rtx)]) >= 0)
31252284Sobrien	    {
31352284Sobrien	      edge e;
314169689Skan	      edge_iterator ei;
31552284Sobrien
31652284Sobrien	      bb = BASIC_BLOCK (i);
31752284Sobrien
31852284Sobrien	      /* End of the basic block.  */
31990075Sobrien	      end_bb (fp);
32052284Sobrien
32152284Sobrien	      /* Now specify the edges to all the successors of this
32252284Sobrien		 basic block.  */
323169689Skan	      FOR_EACH_EDGE (e, ei, bb->succs)
32452284Sobrien		{
32552284Sobrien		  if (e->dest != EXIT_BLOCK_PTR)
32652284Sobrien		    {
327132718Skan		      rtx block_head = BB_HEAD (e->dest);
32852284Sobrien
32952284Sobrien		      draw_edge (fp, INSN_UID (tmp_rtx),
33052284Sobrien				 INSN_UID (block_head),
33152284Sobrien				 next_insn != block_head,
33252284Sobrien				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
33352284Sobrien
33452284Sobrien		      if (block_head == next_insn)
33552284Sobrien			edge_printed = 1;
33652284Sobrien		    }
33752284Sobrien		  else
33852284Sobrien		    {
33952284Sobrien		      draw_edge (fp, INSN_UID (tmp_rtx), 999999,
34052284Sobrien				 next_insn != 0,
34152284Sobrien				 (e->flags & EDGE_ABNORMAL ? 2 : 0));
34252284Sobrien
34352284Sobrien		      if (next_insn == 0)
34452284Sobrien			edge_printed = 1;
34552284Sobrien		    }
34652284Sobrien		}
34752284Sobrien	    }
34852284Sobrien
34952284Sobrien	  if (!edge_printed)
35052284Sobrien	    {
35152284Sobrien	      /* Don't print edges to barriers.  */
35252284Sobrien	      if (next_insn == 0
353169689Skan		  || !BARRIER_P (next_insn))
35452284Sobrien		draw_edge (fp, XINT (tmp_rtx, 0),
35552284Sobrien			   next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
35652284Sobrien	      else
35752284Sobrien		{
35852284Sobrien		  /* We draw the remaining edges in class 3.  We have
35952284Sobrien		     to skip over the barrier since these nodes are
36052284Sobrien		     not printed at all.  */
36152284Sobrien		  do
36252284Sobrien		    next_insn = NEXT_INSN (next_insn);
36352284Sobrien		  while (next_insn
364169689Skan			 && (NOTE_P (next_insn)
365169689Skan			     || BARRIER_P (next_insn)));
36652284Sobrien
36752284Sobrien		  draw_edge (fp, XINT (tmp_rtx, 0),
36852284Sobrien			     next_insn ? INSN_UID (next_insn) : 999999, 0, 3);
36952284Sobrien		}
37052284Sobrien	    }
37152284Sobrien	}
37252284Sobrien
37352284Sobrien      dump_for_graph = 0;
37452284Sobrien
37552284Sobrien      end_fct (fp);
37690075Sobrien
37790075Sobrien      /* Clean up.  */
37890075Sobrien      free (start);
37990075Sobrien      free (end);
38090075Sobrien      free (in_bb_p);
38152284Sobrien    }
38252284Sobrien
38352284Sobrien  fclose (fp);
38452284Sobrien}
38552284Sobrien
38652284Sobrien
38752284Sobrien/* Similar as clean_dump_file, but this time for graph output files.  */
38890075Sobrien
38952284Sobrienvoid
390169689Skanclean_graph_dump_file (const char *base)
39152284Sobrien{
39252284Sobrien  size_t namelen = strlen (base);
39352284Sobrien  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
394169689Skan  char *buf = alloca (namelen + extlen);
39552284Sobrien  FILE *fp;
39652284Sobrien
39752284Sobrien  memcpy (buf, base, namelen);
398169689Skan  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
39952284Sobrien
40052284Sobrien  fp = fopen (buf, "w");
40152284Sobrien
40252284Sobrien  if (fp == NULL)
403132718Skan    fatal_error ("can't open %s: %m", buf);
40452284Sobrien
405169689Skan  gcc_assert (graph_dump_format == vcg);
406169689Skan  fputs ("graph: {\nport_sharing: no\n", fp);
40752284Sobrien
40852284Sobrien  fclose (fp);
40952284Sobrien}
41052284Sobrien
41152284Sobrien
41252284Sobrien/* Do final work on the graph output file.  */
41352284Sobrienvoid
414169689Skanfinish_graph_dump_file (const char *base)
41552284Sobrien{
41652284Sobrien  size_t namelen = strlen (base);
41752284Sobrien  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
418169689Skan  char *buf = alloca (namelen + extlen);
41952284Sobrien  FILE *fp;
42052284Sobrien
42152284Sobrien  memcpy (buf, base, namelen);
422169689Skan  memcpy (buf + namelen, graph_ext[graph_dump_format], extlen);
42352284Sobrien
42452284Sobrien  fp = fopen (buf, "a");
42552284Sobrien  if (fp != NULL)
42652284Sobrien    {
427169689Skan      gcc_assert (graph_dump_format == vcg);
428169689Skan      fputs ("}\n", fp);
42952284Sobrien      fclose (fp);
43052284Sobrien    }
43152284Sobrien}
432