summaryrefslogtreecommitdiffstats
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/Makefile.in4
-rw-r--r--gcc/flags.h11
-rw-r--r--gcc/graph.c486
-rw-r--r--gcc/print-rtl.c97
-rw-r--r--gcc/toplev.c310
6 files changed, 830 insertions, 94 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 815ece7babc..68a8f808a0b 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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>.
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 64d242fbc8c..439786665e0 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -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)
diff --git a/gcc/flags.h b/gcc/flags.h
index 7c853d0b259..f25b0ba282e 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -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
index 00000000000..a60cd42db43
--- /dev/null
+++ b/gcc/graph.c
@@ -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;
+ }
+}
+
+/* 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);
+ }
+}
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 1a0a16d82a8..234b6e45bf4 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -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))
{
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 707da3e09e5..da28bda1862 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -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);
}
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;
OpenPOWER on IntegriCloud