Ulrich Drepper <drepper@cygnus.com>
authorUlrich Drepper <drepper@cygnus.com>
Mon, 23 Nov 1998 16:41:12 +0000 (16:41 +0000)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 23 Nov 1998 16:41:12 +0000 (08:41 -0800)
Ulrich Drepper  <drepper@cygnus.com>
        * Makefile.in (OBJS): Add graph.o
        (graph.o): New dependency list.
        * flags.h: Declare dump_for_graph and define graph_dump_types type.
        * print-rtl.c (dump_for_graph): Define new variable.
        (print_rtx): Rewrite to allow use in graph dumping functions.
        * toplev.c: Declare print_rtl_graph_with_bb, clean_graph_dump_file,
        finish_graph_dump_file.
        Define graph_dump_format.
        (compile_file): If graph dumping is enabled also clear these files.
        Finish graph dump files.
        (rest_of_compilation): Also dump graph information if enabled.
        (main): Recognize -dv to enabled VCG based graph dumping.
        * graph.c: New file.  Graph dumping functions.

From-SVN: r23813

gcc/ChangeLog
gcc/Makefile.in
gcc/flags.h
gcc/graph.c [new file with mode: 0644]
gcc/print-rtl.c
gcc/toplev.c

index 815ece7babcd74dda1d447b8d39e1335531e899a..68a8f808a0bf519d83b8f82b6fc1c4bdec073984 100644 (file)
@@ -1,3 +1,19 @@
+Mon Nov 23 16:40:00 1998  Ulrich Drepper  <drepper@cygnus.com>
+
+        * Makefile.in (OBJS): Add graph.o
+        (graph.o): New dependency list.
+        * flags.h: Declare dump_for_graph and define graph_dump_types type.
+        * print-rtl.c (dump_for_graph): Define new variable.
+        (print_rtx): Rewrite to allow use in graph dumping functions.
+        * toplev.c: Declare print_rtl_graph_with_bb, clean_graph_dump_file,
+        finish_graph_dump_file.
+        Define graph_dump_format.
+        (compile_file): If graph dumping is enabled also clear these files.
+        Finish graph dump files.
+        (rest_of_compilation): Also dump graph information if enabled.
+        (main): Recognize -dv to enabled VCG based graph dumping.
+        * graph.c: New file.  Graph dumping functions.
+
 Mon Nov 23 16:39:04 1998  Richard Henderson  <rth@cygnus.com>
 
         * configure.in: Look for <sys/stat.h>.
index 64d242fbc8c2a4d5f67d59055b1e1b56a2f93ef9..439786665e01b9bbee55046f21a7c15959423147 100644 (file)
@@ -647,7 +647,7 @@ OBJS = toplev.o version.o tree.o print-tree.o stor-layout.o fold-const.o \
  insn-peep.o reorg.o $(SCHED_PREFIX)sched.o final.o recog.o reg-stack.o \
  insn-opinit.o insn-recog.o insn-extract.o insn-output.o insn-emit.o \
  profile.o insn-attrtab.o $(out_object_file) getpwd.o $(EXTRA_OBJS) convert.o \
- mbchar.o dyn-string.o splay-tree.o
+ mbchar.o dyn-string.o splay-tree.o graph.o
 
 # GEN files are listed separately, so they can be built before doing parallel
 #  makes for cc1 or cc1plus.  Otherwise sequent parallel make attempts to load
@@ -1289,6 +1289,8 @@ c-pragma.o: c-pragma.c $(CONFIG_H) system.h $(RTL_H) $(TREE_H) except.h \
 c-iterate.o: c-iterate.c $(CONFIG_H) system.h $(TREE_H) $(RTL_H) c-tree.h \
     flags.h toplev.h $(EXPR_H)
 mbchar.o: mbchar.c $(CONFIG_H) system.h mbchar.h
+graph.o: graph.c $(CONFIG_H) system.h toplev.h flags.h output.h rtl.h \
+    hard-reg-set.h basic-block.h
 
 collect2$(exeext): collect2.o tlink.o hash.o cplus-dem.o underscore.o \
        version.o choose-temp.o mkstemp.o $(LIBDEPS)
index 7c853d0b259a4dfb680fc02879e471e51eb0a795..f25b0ba282ec0adaa52d697d13ecfb5d4c8ca39b 100644 (file)
@@ -502,3 +502,14 @@ extern int current_function_is_thunk;
 /* Value of the -G xx switch, and whether it was passed or not.  */
 extern int g_switch_value;
 extern int g_switch_set;
+
+/* Nonzero if we dump in VCG format, not plain text.  */
+extern int dump_for_graph;
+
+/* Selection of the graph form.  */
+enum graph_dump_types
+{
+  no_graph = 0,
+  vcg
+};
+extern enum graph_dump_types graph_dump_format;
diff --git a/gcc/graph.c b/gcc/graph.c
new file mode 100644 (file)
index 0000000..a60cd42
--- /dev/null
@@ -0,0 +1,486 @@
+/* Output routines for graphical representation.
+   Copyright (C) 1998 Free Software Foundation, Inc.
+   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   This file is part of GNU CC.
+
+   GNU CC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU CC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU CC; see the file COPYING.  If not, write to
+   the Free Software Foundation, 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <config.h>
+#include "system.h"
+
+#include "rtl.h"
+#include "flags.h"
+#include "output.h"
+#include "hard-reg-set.h"
+#include "basic-block.h"
+#include "toplev.h"
+
+static const char *graph_ext[] =
+{
+  /* no_graph */ "",
+  /* vcg */      ".vcg",
+};
+
+/* Output text for new basic block.  */
+static void
+start_fct (fp)
+     FILE *fp;
+{
+
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fprintf (fp, "\
+graph: { title: \"%s\"\nfolding: 1\nhidden: 2\nnode: { title: \"%s.0\" }\n",
+              current_function_name, current_function_name);
+      break;
+    case no_graph:
+      break;
+    }
+}
+
+static void
+start_bb (fp, bb)
+     FILE *fp;
+     int bb;
+{
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fprintf (fp, "\
+graph: {\ntitle: \"%s.BB%d\"\nfolding: 1\ncolor: lightblue\n\
+label: \"basic block %d",
+              current_function_name, bb, bb);
+      break;
+    case no_graph:
+      break;
+    }
+
+#if 0
+  /* FIXME Should this be printed?  It makes the graph significantly larger. */
+
+  /* Print the live-at-start register list.  */
+  fputc ('\n', fp);
+  EXECUTE_IF_SET_IN_REG_SET (basic_block_live_at_start[bb], 0, i,
+                            {
+                              fprintf (fp, " %d", i);
+                              if (i < FIRST_PSEUDO_REGISTER)
+                                fprintf (fp, " [%s]",
+                                         reg_names[i]);
+                            });
+#endif
+
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fputs ("\"\n\n", fp);
+      break;
+    case no_graph:
+      break;
+    }
+}
+
+static int
+node_data (fp, tmp_rtx)
+     FILE *fp;
+     rtx tmp_rtx;
+{
+  int result;
+
+  if (PREV_INSN (tmp_rtx) == 0)
+    {
+      /* This is the first instruction.  Add an edge from the starting
+        block.  */
+      switch (graph_dump_format)
+       {
+       case vcg:
+         fprintf (fp, "\
+edge: { sourcename: \"%s.0\" targetname: \"%s.%d\" }\n",
+                  current_function_name,
+                  current_function_name, XINT (tmp_rtx, 0));
+         break;
+       case no_graph:
+         break;
+       }
+    }
+
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fprintf (fp, "node: {\n  title: \"%s.%d\"\n  color: %s\n  \
+label: \"%s %d\n",
+              current_function_name, XINT (tmp_rtx, 0),
+              GET_CODE (tmp_rtx) == NOTE ? "lightgrey"
+              : GET_CODE (tmp_rtx) == INSN ? "green"
+              : GET_CODE (tmp_rtx) == JUMP_INSN ? "darkgreen"
+              : GET_CODE (tmp_rtx) == CALL_INSN ? "darkgreen"
+              : GET_CODE (tmp_rtx) == CODE_LABEL ?  "\
+darkgrey\n  shape: ellipse" : "white",
+              GET_RTX_NAME (GET_CODE (tmp_rtx)), XINT (tmp_rtx, 0));
+      break;
+    case no_graph:
+      break;
+    }
+
+  /* Print the RTL.  */
+  if (GET_CODE (tmp_rtx) == NOTE)
+    {
+      static const char *note_names[] =
+      {
+       NULL,
+       "deleted",
+       "block_beg",
+       "block_end",
+       "loop_beg",
+       "loop_end",
+       "function_end",
+       "setjmp",
+       "loop_cont",
+       "loop_vtop",
+       "prologue_end",
+       "epilogue_beg",
+       "deleted_label",
+       "function_beg",
+       "eh_region_beg",
+       "eh_region_end",
+       "repeated_line_number",
+       "range_start",
+       "range_end",
+       "live"
+      };
+
+      fprintf (fp, " %s",
+              XINT (tmp_rtx, 4) < 0 ? note_names[-XINT (tmp_rtx, 4)] : "");
+    }
+  else if (GET_RTX_CLASS (GET_CODE (tmp_rtx)) == 'i')
+    result = print_rtl_single (fp, PATTERN (tmp_rtx));
+  else
+    result = print_rtl_single (fp, tmp_rtx);
+
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fputs ("\"\n}\n", fp);
+      break;
+    case no_graph:
+      break;
+    }
+
+  return result;
+}
+
+static void
+draw_edge (fp, from, to, bb_edge, class)
+     FILE *fp;
+     int from;
+     int to;
+     int bb_edge;
+     int class;
+{
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fprintf (fp,
+              "edge: { sourcename: \"%s.%d\" targetname: \"%s.%d\" %s",
+              current_function_name, from,
+              current_function_name, to,
+              bb_edge ? "color: blue " : class ? "color: red " : "");
+      if (class)
+       fprintf (fp, "class: %d ", class);
+      fputs ("}\n", fp);
+      break;
+    case no_graph:
+      break;
+    }
+}
+
+static void
+end_bb (fp, bb)
+     FILE *fp;
+     int bb ATTRIBUTE_UNUSED;
+{
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fputs ("}\n", fp);
+      break;
+    case no_graph:
+      break;
+    }
+}
+
+static void
+end_fct (fp)
+     FILE *fp;
+{
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fprintf (fp, "node: { title: \"%s.999999\" label: \"END\" }\n}\n",
+              current_function_name);
+      break;
+    case no_graph:
+      break;
+    }
+}
+\f
+/* Like print_rtl, but also print out live information for the start of each
+   basic block.  */
+void
+print_rtl_graph_with_bb (base, suffix, rtx_first)
+     const char *base;
+     const char *suffix;
+     rtx rtx_first;
+{
+  register rtx tmp_rtx;
+  size_t namelen = strlen (base);
+  size_t suffixlen = strlen (suffix);
+  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
+  char *buf = (char *) alloca (namelen + suffixlen + extlen);
+  FILE *fp;
+
+  /* Regenerate the basic block information.  */
+  find_basic_blocks (rtx_first, max_reg_num (), NULL);
+
+  memcpy (buf, base, namelen);
+  memcpy (buf + namelen, suffix, suffixlen);
+  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
+
+  fp = fopen (buf, "a");
+  if (fp == NULL)
+    return;
+
+  if (rtx_first == 0)
+    fprintf (fp, "(nil)\n");
+  else
+    {
+      int i, bb;
+      enum bb_state { NOT_IN_BB, IN_ONE_BB, IN_MULTIPLE_BB };
+      int max_uid = get_max_uid ();
+      int *start = (int *) alloca (max_uid * sizeof (int));
+      int *end = (int *) alloca (max_uid * sizeof (int));
+      enum bb_state *in_bb_p = (enum bb_state *)
+       alloca (max_uid * sizeof (enum bb_state));
+      /* Element I is a list of I's predecessors/successors.  */
+      int_list_ptr *s_preds;
+      int_list_ptr *s_succs;
+      /* Element I is the number of predecessors/successors of basic
+        block I.  */
+      int *num_preds;
+      int *num_succs;
+
+      for (i = 0; i < max_uid; ++i)
+       {
+         start[i] = end[i] = -1;
+         in_bb_p[i] = NOT_IN_BB;
+       }
+
+      for (i = n_basic_blocks - 1; i >= 0; --i)
+       {
+         rtx x;
+         start[INSN_UID (basic_block_head[i])] = i;
+         end[INSN_UID (basic_block_end[i])] = i;
+         for (x = basic_block_head[i]; x != NULL_RTX; x = NEXT_INSN (x))
+           {
+             in_bb_p[INSN_UID (x)]
+               = (in_bb_p[INSN_UID (x)] == NOT_IN_BB)
+                ? IN_ONE_BB : IN_MULTIPLE_BB;
+             if (x == basic_block_end[i])
+               break;
+           }
+       }
+
+      /* Get the information about the basic blocks predecessors and
+        successors.  */
+      s_preds = (int_list_ptr *) alloca (n_basic_blocks
+                                        * sizeof (int_list_ptr));
+      s_succs = (int_list_ptr *) alloca (n_basic_blocks
+                                        * sizeof (int_list_ptr));
+      num_preds = (int *) alloca (n_basic_blocks * sizeof (int));
+      num_succs = (int *) alloca (n_basic_blocks * sizeof (int));
+      compute_preds_succs (s_preds, s_succs, num_preds, num_succs);
+
+      /* Tell print-rtl that we want graph output.  */
+      dump_for_graph = 1;
+
+      /* Start new function.  */
+      start_fct (fp);
+
+      for (tmp_rtx = NEXT_INSN (rtx_first); NULL != tmp_rtx;
+          tmp_rtx = NEXT_INSN (tmp_rtx))
+       {
+         int did_output;
+         int edge_printed = 0;
+         rtx next_insn;
+
+         if (start[INSN_UID (tmp_rtx)] < 0 && end[INSN_UID (tmp_rtx)] < 0)
+           {
+             if (GET_CODE (tmp_rtx) == BARRIER)
+               continue;
+             if (GET_CODE (tmp_rtx) == NOTE
+                 && (1 || in_bb_p[INSN_UID (tmp_rtx)] == NOT_IN_BB))
+               continue;
+           }
+
+         if ((bb = start[INSN_UID (tmp_rtx)]) >= 0)
+           {
+             /* We start a subgraph for each basic block.  */
+             start_bb (fp, bb);
+
+             if (bb == 0)
+               draw_edge (fp, 0, INSN_UID (tmp_rtx), 1, 0);
+           }
+
+         /* Print the data for this node.  */
+         did_output = node_data (fp, tmp_rtx);
+         next_insn = next_nonnote_insn (tmp_rtx);
+
+         if ((bb = end[INSN_UID (tmp_rtx)]) >= 0)
+           {
+             int_list_ptr p;
+
+             /* End of the basic block.  */
+             end_bb (fp, bb);
+
+             /* Now specify the edges to all the successors of this
+                basic block.  */
+             for (p = s_succs[bb]; p != NULL; p = p->next)
+               {
+                 int bb_succ = INT_LIST_VAL (p);
+
+                 if (bb_succ >= 0)
+                   {
+                     rtx block_head = BLOCK_HEAD (bb_succ);
+
+                     draw_edge (fp, INSN_UID (tmp_rtx),
+                                INSN_UID (block_head),
+                                next_insn != block_head, 0);
+
+                     if (BLOCK_HEAD (bb_succ) == next_insn)
+                       edge_printed = 1;
+                   }
+                 else if (bb_succ == EXIT_BLOCK)
+                   {
+                     draw_edge (fp, INSN_UID (tmp_rtx), 999999,
+                                next_insn != 0, 0);
+
+                     if (next_insn == 0)
+                       edge_printed = 1;
+                   }
+                 else
+                   abort ();
+               }
+           }
+
+         if (!edge_printed)
+           {
+             /* Don't print edges to barriers.  */
+             if (next_insn == 0
+                 || GET_CODE (next_insn) != BARRIER)
+               draw_edge (fp, XINT (tmp_rtx, 0),
+                          next_insn ? INSN_UID (next_insn) : 999999, 0, 0);
+             else
+               {
+                 /* We draw the remaining edges in class 2.  We have
+                    to skip oevr the barrier since these nodes are
+                    not printed at all.  */
+                 do
+                   next_insn = NEXT_INSN (next_insn);
+                 while (next_insn
+                        && (GET_CODE (next_insn) == NOTE
+                            || GET_CODE (next_insn) == BARRIER));
+
+                 draw_edge (fp, XINT (tmp_rtx, 0),
+                            next_insn ? INSN_UID (next_insn) : 999999, 0, 2);
+               }
+           }
+       }
+
+      dump_for_graph = 0;
+
+      end_fct (fp);
+    }
+
+  fclose (fp);
+}
+
+
+/* Similar as clean_dump_file, but this time for graph output files.  */
+void
+clean_graph_dump_file (base, suffix)
+     const char *base;
+     const char *suffix;
+{
+  size_t namelen = strlen (base);
+  size_t suffixlen = strlen (suffix);
+  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
+  char *buf = (char *) alloca (namelen + extlen + suffixlen);
+  FILE *fp;
+
+  memcpy (buf, base, namelen);
+  memcpy (buf + namelen, suffix, suffixlen);
+  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
+
+  fp = fopen (buf, "w");
+
+  if (fp == NULL)
+    pfatal_with_name (buf);
+
+  switch (graph_dump_format)
+    {
+    case vcg:
+      fputs ("graph: {\nport_sharing: no\n", fp);
+      break;
+    case no_graph:
+      abort ();
+    }
+
+  fclose (fp);
+}
+
+
+/* Do final work on the graph output file.  */
+void
+finish_graph_dump_file (base, suffix)
+     const char *base;
+     const char *suffix;
+{
+  size_t namelen = strlen (base);
+  size_t suffixlen = strlen (suffix);
+  size_t extlen = strlen (graph_ext[graph_dump_format]) + 1;
+  char *buf = (char *) alloca (namelen + suffixlen + extlen);
+  FILE *fp;
+
+  memcpy (buf, base, namelen);
+  memcpy (buf + namelen, suffix, suffixlen);
+  memcpy (buf + namelen + suffixlen, graph_ext[graph_dump_format], extlen);
+
+  fp = fopen (buf, "a");
+  if (fp != NULL)
+    {
+      switch (graph_dump_format)
+       {
+       case vcg:
+         fputs ("}\n", fp);
+         break;
+       case no_graph:
+         abort ();
+       }
+
+      fclose (fp);
+    }
+}
index 1a0a16d82a885226b74302d0e3acbeb2e0f7e669..234b6e45bf418efe307a9c2f750b6e31ee46c4af 100644 (file)
@@ -1,5 +1,5 @@
 /* Print RTL for GNU C Compiler.
-   Copyright (C) 1987, 1988, 1992, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1987, 1988, 1992, 1997, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -60,13 +60,17 @@ extern char **insn_name_ptr;
    This must be defined here so that programs like gencodes can be linked.  */
 int flag_dump_unnumbered = 0;
 
+/* Nonzero if we are dumping graphical description.  */
+int dump_for_graph;
+
 /* Print IN_RTX onto OUTFILE.  This is the recursive part of printing.  */
 
 static void
 print_rtx (in_rtx)
      register rtx in_rtx;
 {
-  register int i, j;
+  register int i = 0;
+  register int j;
   register char *format_ptr;
   register int is_insn;
 
@@ -79,39 +83,54 @@ print_rtx (in_rtx)
 
   if (in_rtx == 0)
     {
-      fprintf (outfile, "(nil)");
+      fputs ("(nil)", outfile);
       sawclose = 1;
       return;
     }
 
-  /* print name of expression code */
-  fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
+  is_insn = (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i');
+
+  /* When printing in VCG format we write INSNs, NOTE, LABEL, and BARRIER
+     in separate nodes and therefore have to handle them special here.  */
+  if (dump_for_graph &&
+      (is_insn || GET_CODE (in_rtx) == NOTE || GET_CODE (in_rtx) == CODE_LABEL
+       || GET_CODE (in_rtx) == BARRIER))
+    {
+      i = 3;
+      indent = 0;
+    }
+  else
+    {
+      /* print name of expression code */
+      fprintf (outfile, "(%s", GET_RTX_NAME (GET_CODE (in_rtx)));
 
-  if (in_rtx->in_struct)
-    fprintf (outfile, "/s");
+      if (in_rtx->in_struct)
+       fputs ("/s", outfile);
 
-  if (in_rtx->volatil)
-    fprintf (outfile, "/v");
+      if (in_rtx->volatil)
+       fputs ("/v", outfile);
 
-  if (in_rtx->unchanging)
-    fprintf (outfile, "/u");
+      if (in_rtx->unchanging)
+       fputs ("/u", outfile);
 
-  if (in_rtx->integrated)
-    fprintf (outfile, "/i");
+      if (in_rtx->integrated)
+       fputs ("/i", outfile);
 
-  if (GET_MODE (in_rtx) != VOIDmode)
-    {
-      /* Print REG_NOTE names for EXPR_LIST and INSN_LIST.  */
-      if (GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST)
-       fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
-      else
-       fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
+      if (GET_MODE (in_rtx) != VOIDmode)
+       {
+         /* Print REG_NOTE names for EXPR_LIST and INSN_LIST.  */
+         if (GET_CODE (in_rtx) == EXPR_LIST || GET_CODE (in_rtx) == INSN_LIST)
+           fprintf (outfile, ":%s", GET_REG_NOTE_NAME (GET_MODE (in_rtx)));
+         else
+           fprintf (outfile, ":%s", GET_MODE_NAME (GET_MODE (in_rtx)));
+       }
     }
 
-  is_insn = (GET_RTX_CLASS (GET_CODE (in_rtx)) == 'i');
-  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx));
+  /* Get the format string and skip the first elements if we have handled
+     them already.  */
+  format_ptr = GET_RTX_FORMAT (GET_CODE (in_rtx)) + i;
 
-  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
+  for (; i < GET_RTX_LENGTH (GET_CODE (in_rtx)); i++)
     switch (*format_ptr++)
       {
       case 'S':
@@ -141,9 +160,10 @@ print_rtx (in_rtx)
          }
 
        if (XSTR (in_rtx, i) == 0)
-         fprintf (outfile, " \"\"");
+         fputs (dump_for_graph ? " \\\"\\\"" : " \"\"", outfile);
        else
-         fprintf (outfile, " (\"%s\")", XSTR (in_rtx, i));
+         fprintf (outfile, dump_for_graph ? " (\\\"%s\\\")" : " (\"%s\")",
+                  XSTR (in_rtx, i));
        sawclose = 1;
        break;
 
@@ -168,7 +188,7 @@ print_rtx (in_rtx)
                     (spaces + (sizeof spaces - 1 - indent * 2)));
            sawclose = 0;
          }
-       fprintf (outfile, "[ ");
+       fputs ("[ ", outfile);
        if (NULL != XVEC (in_rtx, i))
          {
            indent += 2;
@@ -184,7 +204,7 @@ print_rtx (in_rtx)
          fprintf (outfile, "\n%s",
                   (spaces + (sizeof spaces - 1 - indent * 2)));
 
-       fprintf (outfile, "] ");
+       fputs ("] ", outfile);
        sawclose = 1;
        indent -= 2;
        break;
@@ -205,7 +225,7 @@ print_rtx (in_rtx)
            }
          else if (flag_dump_unnumbered
                   && (is_insn || GET_CODE (in_rtx) == NOTE))
-           fprintf (outfile, "#");
+           fputc ('#', outfile);
          else
            fprintf (outfile, " %d", value);
        }
@@ -230,18 +250,18 @@ print_rtx (in_rtx)
        if (XEXP (in_rtx, i) != NULL)
          {
            if (flag_dump_unnumbered)
-             fprintf (outfile, "#");
+             fputc ('#', outfile);
            else
              fprintf (outfile, " %d", INSN_UID (XEXP (in_rtx, i)));
          }
        else
-         fprintf (outfile, " 0");
+         fputs (" 0", outfile);
        sawclose = 0;
        break;
 
       case 'b':
        if (XBITMAP (in_rtx, i) == NULL)
-         fprintf (outfile, " {null}");
+         fputs (" {null}", outfile);
        else
          bitmap_print (outfile, XBITMAP (in_rtx, i), " {", "}");
        sawclose = 0;
@@ -253,7 +273,7 @@ print_rtx (in_rtx)
        break;
 
       case '*':
-       fprintf (outfile, " Unknown");
+       fputs (" Unknown", outfile);
        sawclose = 0;
        break;
 
@@ -276,8 +296,15 @@ print_rtx (in_rtx)
     }
 #endif
 
-  fprintf (outfile, ")");
-  sawclose = 1;
+  if (dump_for_graph
+      && (is_insn || GET_CODE (in_rtx) == NOTE
+         || GET_CODE (in_rtx) == CODE_LABEL || GET_CODE (in_rtx) == BARRIER))
+    sawclose = 0;
+  else
+    {
+      fputc (')', outfile);
+      sawclose = 1;
+    }
 }
 
 /* Print an rtx on the current line of FILE.  Initially indent IND
@@ -386,7 +413,7 @@ print_rtl (outf, rtx_first)
   sawclose = 0;
 
   if (rtx_first == 0)
-    fprintf (outf, "(nil)\n");
+    fputs ("(nil)\n", outf);
   else
     switch (GET_CODE (rtx_first))
       {
index 707da3e09e5c3a27e7c09039bcf8985c6aafe09c..da28bda18623e8339c7f1d5c61f7aa091a506db5 100644 (file)
@@ -212,6 +212,10 @@ static int print_single_switch PROTO((FILE *, int, int, char *, char *, char *,
                                      char *, char *));
 static void print_switch_values PROTO((FILE *, int, int, char *, char *,
                                       char *));
+
+void print_rtl_graph_with_bb PROTO ((const char *, const char *, rtx));
+void clean_graph_dump_file PROTO ((const char *, const char *));
+void finish_graph_dump_file PROTO ((const char *, const char *));
 /* Length of line when printing switch values.  */
 #define MAX_LINE 75
 
@@ -288,6 +292,7 @@ int stack_reg_dump = 0;
 #ifdef MACHINE_DEPENDENT_REORG
 int mach_dep_reorg_dump = 0;
 #endif
+enum graph_dump_types graph_dump_format;
 
 /* Name for output file of assembly code, specified with -o.  */
 
@@ -2606,50 +2611,122 @@ compile_file (name)
        pfatal_with_name (aux_info_file_name);
     }
 
-  /* Clear the dump files file.  */
+  /* Clear the dump files.  */
   if (rtl_dump)
     clean_dump_file (".rtl");
   if (jump_opt_dump)
-    clean_dump_file (".jump");
+    {
+      clean_dump_file (".jump");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".jump");
+    }
   if (addressof_dump)
-    clean_dump_file (".addressof");
+    {
+      clean_dump_file (".addressof");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".addressof");
+    }
   if (cse_dump)
-    clean_dump_file (".cse");
+    {
+      clean_dump_file (".cse");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".cse");
+    }
   if (loop_dump)
-    clean_dump_file (".loop");
+    {
+      clean_dump_file (".loop");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".loop");
+    }
   if (cse2_dump)
-    clean_dump_file (".cse2");
+    {
+      clean_dump_file (".cse2");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".cse2");
+    }
   if (branch_prob_dump)
-    clean_dump_file (".bp");
+    {
+      clean_dump_file (".bp");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".bp");
+    }
   if (flow_dump)
-    clean_dump_file (".flow");
+    {
+      clean_dump_file (".flow");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".flow");
+    }
   if (combine_dump)
-    clean_dump_file (".combine");
+    {
+      clean_dump_file (".combine");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".combine");
+    }
   if (regmove_dump)
-    clean_dump_file (".regmove");
+    {
+      clean_dump_file (".regmove");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".regmove");
+    }
   if (sched_dump)
-    clean_dump_file (".sched");
+    {
+      clean_dump_file (".sched");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".sched");
+    }
   if (local_reg_dump)
-    clean_dump_file (".lreg");
+    {
+      clean_dump_file (".lreg");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".lreg");
+    }
   if (global_reg_dump)
-    clean_dump_file (".greg");
+    {
+      clean_dump_file (".greg");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".greg");
+    }
   if (sched2_dump)
-    clean_dump_file (".sched2");
+    {
+      clean_dump_file (".sched2");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".sched2");
+    }
   if (jump2_opt_dump)
-    clean_dump_file (".jump2");
+    {
+      clean_dump_file (".jump2");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".jump2");
+    }
 #ifdef DELAY_SLOTS
   if (dbr_sched_dump)
-    clean_dump_file (".dbr");
+    {
+      clean_dump_file (".dbr");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".dbr");
+    }
 #endif
   if (gcse_dump)
-    clean_dump_file (".gcse");
+    {
+      clean_dump_file (".gcse");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".gcse");
+    }
 #ifdef STACK_REGS
   if (stack_reg_dump)
-    clean_dump_file (".stack");
+    {
+      clean_dump_file (".stack");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".stack");
+    }
 #endif
 #ifdef MACHINE_DEPENDENT_REORG
   if (mach_dep_reorg_dump)
-    clean_dump_file (".mach");
+    {
+      clean_dump_file (".mach");
+      if (graph_dump_format != no_graph)
+       clean_graph_dump_file (dump_base_name, ".mach");
+    }
 #endif
 
   /* Open assembler code output file.  */
@@ -3119,6 +3196,53 @@ compile_file (name)
       && (ferror (asm_out_file) != 0 || fclose (asm_out_file) != 0))
     fatal_io_error (asm_file_name);
 
+  /* Do whatever is necessary to finish printing the graphs.  */
+  if (graph_dump_format != no_graph)
+    {
+      if (jump_opt_dump)
+       finish_graph_dump_file (dump_base_name, ".jump");
+      if (addressof_dump)
+       finish_graph_dump_file (dump_base_name, ".addressof");
+      if (cse_dump)
+       finish_graph_dump_file (dump_base_name, ".cse");
+      if (loop_dump)
+       finish_graph_dump_file (dump_base_name, ".loop");
+      if (cse2_dump)
+       finish_graph_dump_file (dump_base_name, ".cse2");
+      if (branch_prob_dump)
+       finish_graph_dump_file (dump_base_name, ".bp");
+      if (flow_dump)
+       finish_graph_dump_file (dump_base_name, ".flow");
+      if (combine_dump)
+       finish_graph_dump_file (dump_base_name, ".combine");
+      if (regmove_dump)
+       finish_graph_dump_file (dump_base_name, ".regmove");
+      if (sched_dump)
+       finish_graph_dump_file (dump_base_name, ".sched");
+      if (local_reg_dump)
+       finish_graph_dump_file (dump_base_name, ".lreg");
+      if (global_reg_dump)
+       finish_graph_dump_file (dump_base_name, ".greg");
+      if (sched2_dump)
+       finish_graph_dump_file (dump_base_name, ".sched2");
+      if (jump2_opt_dump)
+       finish_graph_dump_file (dump_base_name, ".jump2");
+#ifdef DELAY_SLOTS
+      if (dbr_sched_dump)
+       finish_graph_dump_file (dump_base_name, ".dbr");
+#endif
+      if (gcse_dump)
+       finish_graph_dump_file (dump_base_name, ".gcse");
+#ifdef STACK_REGS
+      if (stack_reg_dump)
+       finish_graph_dump_file (dump_base_name, ".stack");
+#endif
+#ifdef MACHINE_DEPENDENT_REORG
+      if (mach_dep_reorg_dump)
+       finish_graph_dump_file (dump_base_name, ".mach");
+#endif
+    }
+
   /* Free up memory for the benefit of leak detectors.  */
   free_reg_info ();
 
@@ -3544,28 +3668,40 @@ rest_of_compilation (decl)
                                           !JUMP_AFTER_REGSCAN));
 
       /* Dump rtl code after cse, if we are doing that.  */
-      
+
       if (cse_dump)
-       close_dump_file (print_rtl, insns);
+       {
+         close_dump_file (print_rtl, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".cse", insns);
+       }
     }
 
   purge_addressof (insns);
   reg_scan (insns, max_reg_num (), 1);
 
   if (addressof_dump)
-    dump_rtl (".addressof", decl, print_rtl, insns);
-  
+    {
+      dump_rtl (".addressof", decl, print_rtl, insns);
+      if (graph_dump_format != no_graph)
+       print_rtl_graph_with_bb (dump_base_name, ".addressof", insns);
+    }
+
   /* Perform global cse.  */
 
   if (optimize > 0 && flag_gcse)
     {
       if (gcse_dump)
        open_dump_file (".gcse", IDENTIFIER_POINTER (DECL_NAME (decl)));
-      
+
       TIMEVAR (gcse_time, gcse_main (insns, rtl_dump_file));
 
       if (gcse_dump)
-       close_dump_file (print_rtl, insns);
+       {
+         close_dump_file (print_rtl, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".gcse", insns);
+       }
     }
   /* Move constant computations out of loops.  */
 
@@ -3596,18 +3732,22 @@ rest_of_compilation (decl)
             }
           loop_optimize (insns, rtl_dump_file, flag_unroll_loops, 1);
         });
-      
+
       /* Dump rtl code after loop opt, if we are doing that.  */
-      
+
       if (loop_dump)
-       close_dump_file (print_rtl, insns);
+       {
+         close_dump_file (print_rtl, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".loop", insns);
+       }
     }
 
   if (optimize > 0)
     {
       if (cse2_dump)
        open_dump_file (".cse2", decl_printable_name (decl, 2));
-      
+
       if (flag_rerun_cse_after_loop)
        {
          /* Running another jump optimization pass before the second
@@ -3636,28 +3776,36 @@ rest_of_compilation (decl)
          TIMEVAR (jump_time, reg_scan (insns, max_reg_num (), 0));
          TIMEVAR (jump_time, thread_jumps (insns, max_reg_num (), 0));
        }
-      
+
       /* Dump rtl code after cse, if we are doing that.  */
-      
+
       if (cse2_dump)
-       close_dump_file (print_rtl, insns);
+       {
+         close_dump_file (print_rtl, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".cse2", insns);
+       }
     }
-  
+
   if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
     {
       if (branch_prob_dump)
        open_dump_file (".bp", decl_printable_name (decl, 2));
-    
+
       TIMEVAR
        (branch_prob_time,
         {
           branch_prob (insns, rtl_dump_file);
         });
-      
+
       if (branch_prob_dump)
-       close_dump_file (print_rtl, insns);
+       {
+         close_dump_file (print_rtl, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".bp", insns);
+       }
     }
-  
+
   /* We are no longer anticipating cse in this function, at least.  */
 
   cse_not_expected = 1;
@@ -3708,18 +3856,26 @@ rest_of_compilation (decl)
   /* Dump rtl after flow analysis.  */
 
   if (flow_dump)
-    close_dump_file (print_rtl_with_bb, insns);
-  
+    {
+      close_dump_file (print_rtl_with_bb, insns);
+      if (graph_dump_format != no_graph)
+       print_rtl_graph_with_bb (dump_base_name, ".flow", insns);
+    }
+
   /* If -opt, try combining insns through substitution.  */
 
   if (optimize > 0)
     {
       TIMEVAR (combine_time, combine_instructions (insns, max_reg_num ()));
-      
+
       /* Dump rtl code after insn combination.  */
-      
+
       if (combine_dump)
-       dump_rtl (".combine", decl, print_rtl_with_bb, insns);
+       {
+         dump_rtl (".combine", decl, print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".combine", insns);
+       }
     }
 
   /* Register allocation pre-pass, to reduce number of moves
@@ -3728,12 +3884,16 @@ rest_of_compilation (decl)
     {
       if (regmove_dump)
        open_dump_file (".regmove", decl_printable_name (decl, 2));
-      
+
       TIMEVAR (regmove_time, regmove_optimize (insns, max_reg_num (),
                                               rtl_dump_file));
-      
+
       if (regmove_dump)
-       close_dump_file (print_rtl_with_bb, insns);
+       {
+         close_dump_file (print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".regmove", insns);
+       }
     }
 
   /* Print function header into sched dump now
@@ -3743,16 +3903,20 @@ rest_of_compilation (decl)
     {
       if (sched_dump)
        open_dump_file (".sched", decl_printable_name (decl, 2));
-      
+
       /* Do control and data sched analysis,
         and write some of the results to dump file.  */
 
       TIMEVAR (sched_time, schedule_insns (rtl_dump_file));
-      
+
       /* Dump rtl after instruction scheduling.  */
-      
+
       if (sched_dump)
-       close_dump_file (print_rtl_with_bb, insns);
+       {
+         close_dump_file (print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".sched", insns);
+       }
     }
 
   /* Unless we did stupid register allocation,
@@ -3771,11 +3935,13 @@ rest_of_compilation (decl)
   if (local_reg_dump)
     {
       open_dump_file (".lreg", decl_printable_name (decl, 2));
-      
+
       TIMEVAR (dump_time, dump_flow_info (rtl_dump_file));
       TIMEVAR (dump_time, dump_local_alloc (rtl_dump_file));
-      
+
       close_dump_file (print_rtl_with_bb, insns);
+      if (graph_dump_format != no_graph)
+       print_rtl_graph_with_bb (dump_base_name, ".lreg", insns);
     }
 
   if (global_reg_dump)
@@ -3823,6 +3989,8 @@ rest_of_compilation (decl)
     {
       TIMEVAR (dump_time, dump_global_regs (rtl_dump_file));
       close_dump_file (print_rtl_with_bb, insns);
+      if (graph_dump_format != no_graph)
+       print_rtl_graph_with_bb (dump_base_name, ".greg", insns);
     }
   if (optimize > 0 && flag_schedule_insns_after_reload)
     {
@@ -3837,7 +4005,11 @@ rest_of_compilation (decl)
       /* Dump rtl after post-reorder instruction scheduling.  */
 
       if (sched2_dump)
-       close_dump_file (print_rtl_with_bb, insns);
+       {
+         close_dump_file (print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".sched2", insns);
+       }
     }
 
 #ifdef LEAF_REGISTERS
@@ -3856,11 +4028,15 @@ rest_of_compilation (decl)
       TIMEVAR (jump_time, jump_optimize (insns, JUMP_CROSS_JUMP,
                                         JUMP_NOOP_MOVES,
                                         !JUMP_AFTER_REGSCAN));
-      
+
       /* Dump rtl code after jump, if we are doing that.  */
 
       if (jump2_opt_dump)
-       dump_rtl (".jump2", decl, print_rtl_with_bb, insns);
+       {
+         dump_rtl (".jump2", decl, print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".jump2", insns);
+       }
     }
 
   /* If a machine dependent reorganization is needed, call it.  */
@@ -3868,7 +4044,11 @@ rest_of_compilation (decl)
    MACHINE_DEPENDENT_REORG (insns);
 
    if (mach_dep_reorg_dump)
-     dump_rtl (".mach", decl, print_rtl_with_bb, insns);
+     {
+       dump_rtl (".mach", decl, print_rtl_with_bb, insns);
+       if (graph_dump_format != no_graph)
+        print_rtl_graph_with_bb (dump_base_name, ".mach", insns);
+     }
 #endif
 
   /* If a scheduling pass for delayed branches is to be done,
@@ -3878,9 +4058,13 @@ rest_of_compilation (decl)
   if (optimize > 0 && flag_delayed_branch)
     {
       TIMEVAR (dbr_sched_time, dbr_schedule (insns, rtl_dump_file));
-      
+
       if (dbr_sched_dump)
-       dump_rtl (".dbr", decl, print_rtl_with_bb, insns);
+       {
+         dump_rtl (".dbr", decl, print_rtl_with_bb, insns);
+         if (graph_dump_format != no_graph)
+           print_rtl_graph_with_bb (dump_base_name, ".dbr", insns);
+       }
     }
 #endif
 
@@ -3897,7 +4081,11 @@ rest_of_compilation (decl)
   TIMEVAR (stack_reg_time, reg_to_stack (insns, rtl_dump_file));
 
   if (stack_reg_dump)
-    dump_rtl (".stack", decl, print_rtl_with_bb, insns);
+    {
+      dump_rtl (".stack", decl, print_rtl_with_bb, insns);
+      if (graph_dump_format != no_graph)
+       print_rtl_graph_with_bb (dump_base_name, ".stack", insns);
+    }
 #endif
 
   /* Now turn the rtl into assembler code.  */
@@ -4015,6 +4203,9 @@ rest_of_compilation (decl)
      *except* what is spent in this function.  */
 
   parse_time -= get_run_time () - start_time;
+
+  /* Reset global variables.  */
+  free_basic_block_vars (0);
 }
 \f
 static void
@@ -4548,6 +4739,9 @@ main (argc, argv)
                  case 'N':
                    regmove_dump = 1;
                    break;
+                 case 'v':
+                   graph_dump_format = vcg;
+                   break;
                  case 'y':
                    set_yydebug (1);
                    break;