diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 16 | ||||
-rw-r--r-- | gcc/Makefile.in | 4 | ||||
-rw-r--r-- | gcc/flags.h | 11 | ||||
-rw-r--r-- | gcc/graph.c | 486 | ||||
-rw-r--r-- | gcc/print-rtl.c | 97 | ||||
-rw-r--r-- | gcc/toplev.c | 310 |
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; |