summaryrefslogtreecommitdiff
path: root/gcc/dumpfile.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/dumpfile.c')
-rw-r--r--gcc/dumpfile.c869
1 files changed, 869 insertions, 0 deletions
diff --git a/gcc/dumpfile.c b/gcc/dumpfile.c
new file mode 100644
index 00000000000..92d1409be08
--- /dev/null
+++ b/gcc/dumpfile.c
@@ -0,0 +1,869 @@
+/* Dump infrastructure for optimizations and intermediate representation.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC 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 3, or (at your option) any later
+version.
+
+GCC 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 GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "diagnostic-core.h"
+#include "dumpfile.h"
+#include "gimple-pretty-print.h"
+#include "tree.h"
+
+/* If non-NULL, return one past-the-end of the matching SUBPART of
+ the WHOLE string. */
+#define skip_leading_substring(whole, part) \
+ (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part))
+
+static int pflags; /* current dump_flags */
+static int alt_flags; /* current opt_info flags */
+static FILE *alt_dump_file = NULL;
+
+static void dump_loc (int, FILE *, source_location);
+static int dump_enabled_p (int);
+static FILE *dump_open_alternate_stream (struct dump_file_info *);
+
+/* Table of tree dump switches. This must be consistent with the
+ TREE_DUMP_INDEX enumeration in dumpfile.h. */
+static struct dump_file_info dump_files[TDI_end] =
+{
+ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0},
+ {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
+ 0, 0, 0, 0},
+ {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 1},
+ {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 2},
+ {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 3},
+ {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 4},
+ {".nested", "tree-nested", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 5},
+ {".vcg", "tree-vcg", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 6},
+ {".ads", "ada-spec", NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 7},
+#define FIRST_AUTO_NUMBERED_DUMP 8
+
+ {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
+ 0, 0, 0, 0},
+ {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL,
+ 0, 0, 0, 0},
+ {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
+ 0, 0, 0, 0},
+};
+
+/* Dynamically registered tree dump files and switches. */
+static struct dump_file_info *extra_dump_files;
+static size_t extra_dump_files_in_use;
+static size_t extra_dump_files_alloced;
+
+/* Define a name->number mapping for a dump flag value. */
+struct dump_option_value_info
+{
+ const char *const name; /* the name of the value */
+ const int value; /* the value of the name */
+};
+
+/* Table of dump options. This must be consistent with the TDF_* flags
+ in dumpfile.h and opt_info_options below. */
+static const struct dump_option_value_info dump_options[] =
+{
+ {"address", TDF_ADDRESS},
+ {"asmname", TDF_ASMNAME},
+ {"slim", TDF_SLIM},
+ {"raw", TDF_RAW},
+ {"graph", TDF_GRAPH},
+ {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
+ | MSG_MISSED_OPTIMIZATION
+ | MSG_NOTE)},
+ {"cselib", TDF_CSELIB},
+ {"stats", TDF_STATS},
+ {"blocks", TDF_BLOCKS},
+ {"vops", TDF_VOPS},
+ {"lineno", TDF_LINENO},
+ {"uid", TDF_UID},
+ {"stmtaddr", TDF_STMTADDR},
+ {"memsyms", TDF_MEMSYMS},
+ {"verbose", TDF_VERBOSE},
+ {"eh", TDF_EH},
+ {"alias", TDF_ALIAS},
+ {"nouid", TDF_NOUID},
+ {"enumerate_locals", TDF_ENUMERATE_LOCALS},
+ {"scev", TDF_SCEV},
+ {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
+ | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
+ | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)},
+ {NULL, 0}
+};
+
+/* A subset of the dump_options table which is used for opt-info
+ options. This must be consistent with the MSG_* flags in
+ dump_options.
+ */
+static const struct dump_option_value_info opt_info_options[] =
+{
+ {"optimized", MSG_OPTIMIZED_LOCATIONS},
+ {"missed", MSG_MISSED_OPTIMIZATION},
+ {"note", MSG_NOTE},
+ {"optall", (MSG_OPTIMIZED_LOCATIONS
+ | MSG_MISSED_OPTIMIZATION
+ | MSG_NOTE)},
+ {NULL, 0}
+};
+
+unsigned int
+dump_register (const char *suffix, const char *swtch, const char *glob,
+ int flags)
+{
+ static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
+ int num = next_dump++;
+
+ size_t count = extra_dump_files_in_use++;
+
+ if (count >= extra_dump_files_alloced)
+ {
+ if (extra_dump_files_alloced == 0)
+ extra_dump_files_alloced = 32;
+ else
+ extra_dump_files_alloced *= 2;
+ extra_dump_files = XRESIZEVEC (struct dump_file_info,
+ extra_dump_files,
+ extra_dump_files_alloced);
+ }
+
+ memset (&extra_dump_files[count], 0, sizeof (struct dump_file_info));
+ extra_dump_files[count].suffix = suffix;
+ extra_dump_files[count].swtch = swtch;
+ extra_dump_files[count].glob = glob;
+ extra_dump_files[count].pflags = flags;
+ extra_dump_files[count].num = num;
+
+ return count + TDI_end;
+}
+
+
+/* Return the dump_file_info for the given phase. */
+
+struct dump_file_info *
+get_dump_file_info (int phase)
+{
+ if (phase < TDI_end)
+ return &dump_files[phase];
+ else if ((size_t) (phase - TDI_end) >= extra_dump_files_in_use)
+ return NULL;
+ else
+ return extra_dump_files + (phase - TDI_end);
+}
+
+
+/* Return the name of the dump file for the given phase.
+ If the dump is not enabled, returns NULL. */
+
+char *
+get_dump_file_name (int phase)
+{
+ char dump_id[10];
+ struct dump_file_info *dfi;
+
+ if (phase == TDI_none)
+ return NULL;
+
+ dfi = get_dump_file_info (phase);
+ if (dfi->pstate == 0)
+ return NULL;
+
+ /* If available, use the command line dump filename. */
+ if (dfi->pfilename)
+ return xstrdup (dfi->pfilename);
+
+ if (dfi->num < 0)
+ dump_id[0] = '\0';
+ else
+ {
+ char suffix;
+ if (dfi->pflags & TDF_TREE)
+ suffix = 't';
+ else if (dfi->pflags & TDF_IPA)
+ suffix = 'i';
+ else
+ suffix = 'r';
+
+ if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
+ dump_id[0] = '\0';
+ }
+
+ return concat (dump_base_name, dump_id, dfi->suffix, NULL);
+}
+
+/* For a given DFI, open an alternate dump filename (which could also
+ be a standard stream such as stdout/stderr). If the alternate dump
+ file cannot be opened, return NULL. */
+
+static FILE *
+dump_open_alternate_stream (struct dump_file_info *dfi)
+{
+ FILE *stream ;
+ if (!dfi->alt_filename)
+ return NULL;
+
+ if (dfi->alt_stream)
+ return dfi->alt_stream;
+
+ stream = strcmp("stderr", dfi->alt_filename) == 0
+ ? stderr
+ : strcmp("stdout", dfi->alt_filename) == 0
+ ? stdout
+ : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
+
+ if (!stream)
+ error ("could not open dump file %qs: %m", dfi->alt_filename);
+ else
+ dfi->alt_state = 1;
+
+ return stream;
+}
+
+/* Print source location on DFILE if enabled. */
+
+void
+dump_loc (int dump_kind, FILE *dfile, source_location loc)
+{
+ /* Currently vectorization passes print location information. */
+ if (dump_kind)
+ {
+ if (loc == UNKNOWN_LOCATION)
+ fprintf (dfile, "\n%s:%d: note: ",
+ DECL_SOURCE_FILE (current_function_decl),
+ DECL_SOURCE_LINE (current_function_decl));
+ else
+ fprintf (dfile, "\n%d: ", LOCATION_LINE (loc));
+ }
+}
+
+/* Dump gimple statement GS with SPC indentation spaces and
+ EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
+
+void
+dump_gimple_stmt (int dump_kind, int extra_dump_flags, gimple gs, int spc)
+{
+ if (dump_file && (dump_kind & pflags))
+ print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
+}
+
+/* Similar to dump_gimple_stmt, except additionally print source location. */
+
+void
+dump_gimple_stmt_loc (int dump_kind, source_location loc, int extra_dump_flags,
+ gimple gs, int spc)
+{
+ if (dump_file && (dump_kind & pflags))
+ {
+ dump_loc (dump_kind, dump_file, loc);
+ print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
+ }
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ {
+ dump_loc (dump_kind, alt_dump_file, loc);
+ print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
+ }
+}
+
+/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
+ DUMP_KIND is enabled. */
+
+void
+dump_generic_expr (int dump_kind, int extra_dump_flags, tree t)
+{
+ if (dump_file && (dump_kind & pflags))
+ print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
+}
+
+
+/* Similar to dump_generic_expr, except additionally print the source
+ location. */
+
+void
+dump_generic_expr_loc (int dump_kind, source_location loc,
+ int extra_dump_flags, tree t)
+{
+ if (dump_file && (dump_kind & pflags))
+ {
+ dump_loc (dump_kind, dump_file, loc);
+ print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
+ }
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ {
+ dump_loc (dump_kind, alt_dump_file, loc);
+ print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
+ }
+}
+
+/* Output a formatted message using FORMAT on appropriate dump streams. */
+
+void
+dump_printf (int dump_kind, const char *format, ...)
+{
+ if (dump_file && (dump_kind & pflags))
+ {
+ va_list ap;
+ va_start (ap, format);
+ vfprintf (dump_file, format, ap);
+ va_end (ap);
+ }
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ {
+ va_list ap;
+ va_start (ap, format);
+ vfprintf (alt_dump_file, format, ap);
+ va_end (ap);
+ }
+}
+
+/* Similar to dump_printf, except source location is also printed. */
+
+void
+dump_printf_loc (int dump_kind, source_location loc, const char *format, ...)
+{
+ if (dump_file && (dump_kind & pflags))
+ {
+ va_list ap;
+ dump_loc (dump_kind, dump_file, loc);
+ va_start (ap, format);
+ vfprintf (dump_file, format, ap);
+ va_end (ap);
+ }
+
+ if (alt_dump_file && (dump_kind & alt_flags))
+ {
+ va_list ap;
+ dump_loc (dump_kind, alt_dump_file, loc);
+ va_start (ap, format);
+ vfprintf (alt_dump_file, format, ap);
+ va_end (ap);
+ }
+}
+
+/* Start a dump for PHASE. Store user-supplied dump flags in
+ *FLAG_PTR. Return the number of streams opened. Set globals
+ DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
+ set dump_flags appropriately for both pass dump stream and opt-info
+ stream. */
+
+int
+dump_start (int phase, int *flag_ptr)
+{
+ int count = 0;
+ char *name;
+ struct dump_file_info *dfi;
+ FILE *stream;
+ if (phase == TDI_none || !dump_enabled_p (phase))
+ return 0;
+
+ dfi = get_dump_file_info (phase);
+ name = get_dump_file_name (phase);
+ if (name)
+ {
+ stream = strcmp("stderr", name) == 0
+ ? stderr
+ : strcmp("stdout", name) == 0
+ ? stdout
+ : fopen (name, dfi->pstate < 0 ? "w" : "a");
+ if (!stream)
+ error ("could not open dump file %qs: %m", name);
+ else
+ {
+ dfi->pstate = 1;
+ count++;
+ }
+ free (name);
+ dfi->pstream = stream;
+ dump_file = dfi->pstream;
+ /* Initialize current dump flags. */
+ pflags = dfi->pflags;
+ }
+
+ stream = dump_open_alternate_stream (dfi);
+ if (stream)
+ {
+ dfi->alt_stream = stream;
+ count++;
+ alt_dump_file = dfi->alt_stream;
+ /* Initialize current opt-info flags. */
+ alt_flags = dfi->alt_flags;
+ }
+
+ if (flag_ptr)
+ *flag_ptr = dfi->pflags;
+
+ return count;
+}
+
+/* Finish a tree dump for PHASE and close associated dump streams. Also
+ reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
+
+void
+dump_finish (int phase)
+{
+ struct dump_file_info *dfi;
+
+ if (phase < 0)
+ return;
+ dfi = get_dump_file_info (phase);
+ if (dfi->pstream)
+ fclose (dfi->pstream);
+
+ if (dfi->alt_stream && strcmp("stderr", dfi->alt_filename) != 0
+ && strcmp("stdout", dfi->alt_filename) != 0)
+ fclose (dfi->alt_stream);
+
+ dfi->alt_stream = NULL;
+ dfi->pstream = NULL;
+ dump_file = NULL;
+ alt_dump_file = NULL;
+ dump_flags = TDI_none;
+ alt_flags = 0;
+ pflags = 0;
+}
+
+/* Begin a tree dump for PHASE. Stores any user supplied flag in
+ *FLAG_PTR and returns a stream to write to. If the dump is not
+ enabled, returns NULL.
+ Multiple calls will reopen and append to the dump file. */
+
+FILE *
+dump_begin (int phase, int *flag_ptr)
+{
+ char *name;
+ struct dump_file_info *dfi;
+ FILE *stream;
+
+ if (phase == TDI_none || !dump_enabled_p (phase))
+ return NULL;
+
+ name = get_dump_file_name (phase);
+ if (!name)
+ return NULL;
+ dfi = get_dump_file_info (phase);
+
+ stream = strcmp("stderr", name) == 0
+ ? stderr
+ : strcmp("stdout", name) == 0
+ ? stdout
+ : fopen (name, dfi->pstate < 0 ? "w" : "a");
+
+ if (!stream)
+ error ("could not open dump file %qs: %m", name);
+ else
+ dfi->pstate = 1;
+ free (name);
+
+ if (flag_ptr)
+ *flag_ptr = dfi->pflags;
+
+ /* Initialize current flags */
+ pflags = dfi->pflags;
+ return stream;
+}
+
+/* Returns nonzero if dump PHASE is enabled for at least one stream.
+ If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
+ any phase. */
+
+int
+dump_enabled_p (int phase)
+{
+ if (phase == TDI_tree_all)
+ {
+ size_t i;
+ for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
+ if (dump_files[i].pstate || dump_files[i].alt_state)
+ return 1;
+ for (i = 0; i < extra_dump_files_in_use; i++)
+ if (extra_dump_files[i].pstate || extra_dump_files[i].alt_state)
+ return 1;
+ return 0;
+ }
+ else
+ {
+ struct dump_file_info *dfi = get_dump_file_info (phase);
+ return dfi->pstate || dfi->alt_state;
+ }
+}
+
+/* Returns nonzero if tree dump PHASE has been initialized. */
+
+int
+dump_initialized_p (int phase)
+{
+ struct dump_file_info *dfi = get_dump_file_info (phase);
+ return dfi->pstate > 0 || dfi->alt_state > 0;
+}
+
+/* Returns the switch name of PHASE. */
+
+const char *
+dump_flag_name (int phase)
+{
+ struct dump_file_info *dfi = get_dump_file_info (phase);
+ return dfi->swtch;
+}
+
+/* Finish a tree dump for PHASE. STREAM is the stream created by
+ dump_begin. */
+
+void
+dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
+{
+ if (stream != stderr && stream != stdout)
+ fclose (stream);
+}
+
+/* Enable all tree dumps with FLAGS on FILENAME. Return number of
+ enabled tree dumps. */
+
+static int
+dump_enable_all (int flags, const char *filename)
+{
+ int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
+ int n = 0;
+ size_t i;
+
+ for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
+ {
+ if ((dump_files[i].pflags & ir_dump_type))
+ {
+ const char *old_filename = dump_files[i].pfilename;
+ dump_files[i].pstate = -1;
+ dump_files[i].pflags |= flags;
+ n++;
+ /* Override the existing filename. */
+ if (filename)
+ {
+ dump_files[i].pfilename = xstrdup (filename);
+ /* Since it is a command-line provided file, which is
+ common to all the phases, use it in append mode. */
+ dump_files[i].pstate = 1;
+ }
+ if (old_filename && filename != old_filename)
+ free (CONST_CAST (char *, old_filename));
+ }
+ }
+
+ for (i = 0; i < extra_dump_files_in_use; i++)
+ {
+ if ((extra_dump_files[i].pflags & ir_dump_type))
+ {
+ const char *old_filename = extra_dump_files[i].pfilename;
+ extra_dump_files[i].pstate = -1;
+ extra_dump_files[i].pflags |= flags;
+ n++;
+ /* Override the existing filename. */
+ if (filename)
+ {
+ extra_dump_files[i].pfilename = xstrdup (filename);
+ /* Since it is a command-line provided file, which is
+ common to all the phases, use it in append mode. */
+ extra_dump_files[i].pstate = 1;
+ }
+ if (old_filename && filename != old_filename)
+ free (CONST_CAST (char *, old_filename));
+ }
+ }
+
+ return n;
+}
+
+/* Enable opt-info dumps on all IR_DUMP_TYPE passes with FLAGS on
+ FILENAME. Return the number of enabled dumps. */
+
+static int
+opt_info_enable_all (int ir_dump_type, int flags, const char *filename)
+{
+ int n = 0;
+ size_t i;
+
+ for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
+ {
+ if ((dump_files[i].pflags & ir_dump_type))
+ {
+ const char *old_filename = dump_files[i].alt_filename;
+ /* Since this file is shared among different passes, it
+ should be opened in append mode. */
+ dump_files[i].alt_state = 1;
+ dump_files[i].alt_flags |= flags;
+ n++;
+ /* Override the existing filename. */
+ if (filename)
+ dump_files[i].alt_filename = xstrdup (filename);
+ if (old_filename && filename != old_filename)
+ free (CONST_CAST (char *, old_filename));
+ }
+ }
+
+ for (i = 0; i < extra_dump_files_in_use; i++)
+ {
+ if ((extra_dump_files[i].pflags & ir_dump_type))
+ {
+ const char *old_filename = extra_dump_files[i].alt_filename;
+ /* Since this file is shared among different passes, it
+ should be opened in append mode. */
+ extra_dump_files[i].alt_state = 1;
+ extra_dump_files[i].alt_flags |= flags;
+ n++;
+ /* Override the existing filename. */
+ if (filename)
+ extra_dump_files[i].alt_filename = xstrdup (filename);
+ if (old_filename && filename != old_filename)
+ free (CONST_CAST (char *, old_filename));
+ }
+ }
+
+ return n;
+}
+
+/* Parse ARG as a dump switch. Return nonzero if it is, and store the
+ relevant details in the dump_files array. */
+
+static int
+dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
+{
+ const char *option_value;
+ const char *ptr;
+ int flags;
+
+ if (doglob && !dfi->glob)
+ return 0;
+
+ option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
+ if (!option_value)
+ return 0;
+
+ if (*option_value && *option_value != '-' && *option_value != '=')
+ return 0;
+
+ ptr = option_value;
+ flags = 0;
+
+ while (*ptr)
+ {
+ const struct dump_option_value_info *option_ptr;
+ const char *end_ptr;
+ const char *eq_ptr;
+ unsigned length;
+
+ while (*ptr == '-')
+ ptr++;
+ end_ptr = strchr (ptr, '-');
+ eq_ptr = strchr (ptr, '=');
+
+ if (eq_ptr && !end_ptr)
+ end_ptr = eq_ptr;
+
+ if (!end_ptr)
+ end_ptr = ptr + strlen (ptr);
+ length = end_ptr - ptr;
+
+ for (option_ptr = dump_options; option_ptr->name; option_ptr++)
+ if (strlen (option_ptr->name) == length
+ && !memcmp (option_ptr->name, ptr, length))
+ {
+ flags |= option_ptr->value;
+ goto found;
+ }
+
+ if (*ptr == '=')
+ {
+ /* Interpret rest of the argument as a dump filename. This
+ filename overrides other command line filenames. */
+ if (dfi->pfilename)
+ free (CONST_CAST (char *, dfi->pfilename));
+ dfi->pfilename = xstrdup (ptr + 1);
+ break;
+ }
+ else
+ warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
+ length, ptr, dfi->swtch);
+ found:;
+ ptr = end_ptr;
+ }
+
+ dfi->pstate = -1;
+ dfi->pflags |= flags;
+
+ /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
+ known dumps. */
+ if (dfi->suffix == NULL)
+ dump_enable_all (dfi->pflags, dfi->pfilename);
+
+ return 1;
+}
+
+int
+dump_switch_p (const char *arg)
+{
+ size_t i;
+ int any = 0;
+
+ for (i = TDI_none + 1; i != TDI_end; i++)
+ any |= dump_switch_p_1 (arg, &dump_files[i], false);
+
+ /* Don't glob if we got a hit already */
+ if (!any)
+ for (i = TDI_none + 1; i != TDI_end; i++)
+ any |= dump_switch_p_1 (arg, &dump_files[i], true);
+
+ for (i = 0; i < extra_dump_files_in_use; i++)
+ any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
+
+ if (!any)
+ for (i = 0; i < extra_dump_files_in_use; i++)
+ any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
+
+
+ return any;
+}
+
+/* Parse ARG as a -fopt-info switch and store flags and filename.
+ Return non-zero if it is a recognized switch. */
+
+static int
+opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
+{
+ const char *option_value;
+ const char *ptr;
+
+ option_value = arg;
+ ptr = option_value;
+
+ *filename = NULL;
+ *flags = 0;
+
+ if (!ptr)
+ return 1;
+
+ while (*ptr)
+ {
+ const struct dump_option_value_info *option_ptr;
+ const char *end_ptr;
+ const char *eq_ptr;
+ unsigned length;
+
+ while (*ptr == '-')
+ ptr++;
+ end_ptr = strchr (ptr, '-');
+ eq_ptr = strchr (ptr, '=');
+
+ if (eq_ptr && !end_ptr)
+ end_ptr = eq_ptr;
+
+ if (!end_ptr)
+ end_ptr = ptr + strlen (ptr);
+ length = end_ptr - ptr;
+
+ for (option_ptr = opt_info_options; option_ptr->name; option_ptr++)
+ if (strlen (option_ptr->name) == length
+ && !memcmp (option_ptr->name, ptr, length))
+ {
+ *flags |= option_ptr->value;
+ goto found;
+ }
+
+ if (*ptr == '=')
+ {
+ /* Interpret rest of the argument as a dump filename. This
+ filename overrides other command line filenames. */
+ *filename = xstrdup (ptr + 1);
+ break;
+ }
+ else
+ warning (0, "ignoring unknown option %q.*s in %<-fopt-info=%s%>",
+ length, ptr, arg);
+ found:;
+ ptr = end_ptr;
+ }
+
+ return 1;
+}
+
+/* Return non-zero if ARG is a recognized switch for
+ -fopt-info. Return zero otherwise. */
+
+int
+opt_info_switch_p (const char *arg)
+{
+ int flags;
+ char *filename;
+
+ opt_info_switch_p_1 (arg, &flags, &filename);
+
+ if (!filename)
+ filename = xstrdup ("stderr");
+ if (!flags)
+ flags = MSG_ALL;
+
+ return opt_info_enable_all ((TDF_TREE | TDF_RTL | TDF_IPA), flags, filename);
+}
+
+/* Return true if any dumps are enabled for the given MSG_TYPE, false
+ otherwise. */
+
+bool
+dump_kind_p (int msg_type)
+{
+ if (!current_function_decl)
+ return 0;
+ return ((msg_type & pflags) || (msg_type & alt_flags));
+}
+
+/* Print basic block on the dump streams. */
+
+void
+dump_basic_block (int dump_kind, basic_block bb, int indent)
+{
+ if (dump_file && (dump_kind & pflags))
+ dump_bb (dump_file, bb, indent, TDF_DETAILS);
+ if (alt_dump_file && (dump_kind & alt_flags))
+ dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
+}
+
+/* Print information from the combine pass on dump_file. */
+
+void
+print_combine_total_stats (void)
+{
+ if (dump_file)
+ dump_combine_total_stats (dump_file);
+}
+
+/* Enable RTL dump for all the RTL passes. */
+
+bool
+enable_rtl_dump_file (void)
+{
+ return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
+}