diff gcc/dumpfile.c @ 16:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents
children 84e7813d76e9
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/dumpfile.c	Fri Oct 27 22:46:09 2017 +0900
@@ -0,0 +1,1038 @@
+/* Dump infrastructure for optimizations and intermediate representation.
+   Copyright (C) 2012-2017 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 "options.h"
+#include "tree.h"
+#include "gimple-pretty-print.h"
+#include "diagnostic-core.h"
+#include "dumpfile.h"
+#include "context.h"
+#include "profile-count.h"
+#include "tree-cfg.h"
+#include "langhooks.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 dump_flags_t pflags;		      /* current dump_flags */
+static dump_flags_t alt_flags;		      /* current opt_info flags */
+
+static void dump_loc (dump_flags_t, FILE *, source_location);
+static FILE *dump_open_alternate_stream (struct dump_file_info *);
+
+/* These are currently used for communicating between passes.
+   However, instead of accessing them directly, the passes can use
+   dump_printf () for dumps.  */
+FILE *dump_file = NULL;
+FILE *alt_dump_file = NULL;
+const char *dump_file_name;
+dump_flags_t dump_flags;
+
+#define DUMP_FILE_INFO(suffix, swtch, dkind, num) \
+  {suffix, swtch, NULL, NULL, NULL, NULL, NULL, dkind, 0, 0, 0, 0, 0, num, \
+   false, false}
+
+/* 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] =
+{
+  DUMP_FILE_INFO (NULL, NULL, DK_none, 0),
+  DUMP_FILE_INFO (".cgraph", "ipa-cgraph", DK_ipa, 0),
+  DUMP_FILE_INFO (".type-inheritance", "ipa-type-inheritance", DK_ipa, 0),
+  DUMP_FILE_INFO (".ipa-clones", "ipa-clones", DK_ipa, 0),
+  DUMP_FILE_INFO (".original", "tree-original", DK_tree, 0),
+  DUMP_FILE_INFO (".gimple", "tree-gimple", DK_tree, 0),
+  DUMP_FILE_INFO (".nested", "tree-nested", DK_tree, 0),
+#define FIRST_AUTO_NUMBERED_DUMP 1
+#define FIRST_ME_AUTO_NUMBERED_DUMP 3
+
+  DUMP_FILE_INFO (NULL, "lang-all", DK_lang, 0),
+  DUMP_FILE_INFO (NULL, "tree-all", DK_tree, 0),
+  DUMP_FILE_INFO (NULL, "rtl-all", DK_rtl, 0),
+  DUMP_FILE_INFO (NULL, "ipa-all", DK_ipa, 0),
+};
+
+/* 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 dump_flags_t 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},
+  {"eh", TDF_EH},
+  {"alias", TDF_ALIAS},
+  {"nouid", TDF_NOUID},
+  {"enumerate_locals", TDF_ENUMERATE_LOCALS},
+  {"scev", TDF_SCEV},
+  {"gimple", TDF_GIMPLE},
+  {"folding", TDF_FOLDING},
+  {"optimized", MSG_OPTIMIZED_LOCATIONS},
+  {"missed", MSG_MISSED_OPTIMIZATION},
+  {"note", MSG_NOTE},
+  {"optall", MSG_ALL},
+  {"all", dump_flags_t (~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
+			| TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
+			| TDF_ENUMERATE_LOCALS | TDF_SCEV | TDF_GIMPLE))},
+  {NULL, 0}
+};
+
+/* A subset of the dump_options table which is used for -fopt-info
+   types. This must be consistent with the MSG_* flags in dumpfile.h.
+ */
+static const struct dump_option_value_info optinfo_verbosity_options[] =
+{
+  {"optimized", MSG_OPTIMIZED_LOCATIONS},
+  {"missed", MSG_MISSED_OPTIMIZATION},
+  {"note", MSG_NOTE},
+  {"all", MSG_ALL},
+  {NULL, 0}
+};
+
+/* Flags used for -fopt-info groups.  */
+static const struct dump_option_value_info optgroup_options[] =
+{
+  {"ipa", OPTGROUP_IPA},
+  {"loop", OPTGROUP_LOOP},
+  {"inline", OPTGROUP_INLINE},
+  {"omp", OPTGROUP_OMP},
+  {"vec", OPTGROUP_VEC},
+  {"optall", OPTGROUP_ALL},
+  {NULL, 0}
+};
+
+gcc::dump_manager::dump_manager ():
+  m_next_dump (FIRST_AUTO_NUMBERED_DUMP),
+  m_extra_dump_files (NULL),
+  m_extra_dump_files_in_use (0),
+  m_extra_dump_files_alloced (0)
+{
+}
+
+gcc::dump_manager::~dump_manager ()
+{
+  for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
+    {
+      dump_file_info *dfi = &m_extra_dump_files[i];
+      /* suffix, swtch, glob are statically allocated for the entries
+	 in dump_files, and for statistics, but are dynamically allocated
+	 for those for passes.  */
+      if (dfi->owns_strings)
+	{
+	  XDELETEVEC (const_cast <char *> (dfi->suffix));
+	  XDELETEVEC (const_cast <char *> (dfi->swtch));
+	  XDELETEVEC (const_cast <char *> (dfi->glob));
+	}
+      /* These, if non-NULL, are always dynamically allocated.  */
+      XDELETEVEC (const_cast <char *> (dfi->pfilename));
+      XDELETEVEC (const_cast <char *> (dfi->alt_filename));
+    }
+  XDELETEVEC (m_extra_dump_files);
+}
+
+unsigned int
+gcc::dump_manager::
+dump_register (const char *suffix, const char *swtch, const char *glob,
+	       dump_kind dkind, int optgroup_flags, bool take_ownership)
+{
+  int num = m_next_dump++;
+
+  size_t count = m_extra_dump_files_in_use++;
+
+  if (count >= m_extra_dump_files_alloced)
+    {
+      if (m_extra_dump_files_alloced == 0)
+	m_extra_dump_files_alloced = 512;
+      else
+	m_extra_dump_files_alloced *= 2;
+      m_extra_dump_files = XRESIZEVEC (struct dump_file_info,
+				       m_extra_dump_files,
+				       m_extra_dump_files_alloced);
+
+      /* Construct a new object in the space allocated above.  */
+      new (m_extra_dump_files + count) dump_file_info ();
+    }
+  else
+    {
+      /* Zero out the already constructed object.  */
+      m_extra_dump_files[count] = dump_file_info ();
+    }
+
+  m_extra_dump_files[count].suffix = suffix;
+  m_extra_dump_files[count].swtch = swtch;
+  m_extra_dump_files[count].glob = glob;
+  m_extra_dump_files[count].dkind = dkind;
+  m_extra_dump_files[count].optgroup_flags = optgroup_flags;
+  m_extra_dump_files[count].num = num;
+  m_extra_dump_files[count].owns_strings = take_ownership;
+
+  return count + TDI_end;
+}
+
+
+/* Allow languages and middle-end to register their dumps before the
+   optimization passes.  */
+
+void
+gcc::dump_manager::
+register_dumps ()
+{
+  lang_hooks.register_dumps (this);
+  /* If this assert fails, some FE registered more than
+     FIRST_ME_AUTO_NUMBERED_DUMP - FIRST_AUTO_NUMBERED_DUMP
+     dump files.  Bump FIRST_ME_AUTO_NUMBERED_DUMP accordingly.  */
+  gcc_assert (m_next_dump <= FIRST_ME_AUTO_NUMBERED_DUMP);
+  m_next_dump = FIRST_ME_AUTO_NUMBERED_DUMP;
+  dump_files[TDI_original].num = m_next_dump++;
+  dump_files[TDI_gimple].num = m_next_dump++;
+  dump_files[TDI_nested].num = m_next_dump++;
+}
+
+
+/* Return the dump_file_info for the given phase.  */
+
+struct dump_file_info *
+gcc::dump_manager::
+get_dump_file_info (int phase) const
+{
+  if (phase < TDI_end)
+    return &dump_files[phase];
+  else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
+    return NULL;
+  else
+    return m_extra_dump_files + (phase - TDI_end);
+}
+
+/* Locate the dump_file_info with swtch equal to SWTCH,
+   or return NULL if no such dump_file_info exists.  */
+
+struct dump_file_info *
+gcc::dump_manager::
+get_dump_file_info_by_switch (const char *swtch) const
+{
+  for (unsigned i = 0; i < m_extra_dump_files_in_use; i++)
+    if (0 == strcmp (m_extra_dump_files[i].swtch, swtch))
+      return &m_extra_dump_files[i];
+
+  /* Not found.  */
+  return NULL;
+}
+
+
+/* Return the name of the dump file for the given phase.
+   The caller is responsible for calling free on the returned
+   buffer.
+   If the dump is not enabled, returns NULL.  */
+
+char *
+gcc::dump_manager::
+get_dump_file_name (int phase) const
+{
+  struct dump_file_info *dfi;
+
+  if (phase == TDI_none)
+    return NULL;
+
+  dfi = get_dump_file_info (phase);
+
+  return get_dump_file_name (dfi);
+}
+
+/* Return the name of the dump file for the given dump_file_info.
+   The caller is responsible for calling free on the returned
+   buffer.
+   If the dump is not enabled, returns NULL.  */
+
+char *
+gcc::dump_manager::
+get_dump_file_name (struct dump_file_info *dfi) const
+{
+  char dump_id[10];
+
+  gcc_assert (dfi);
+
+  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
+    {
+      /* (null), LANG, TREE, RTL, IPA.  */
+      char suffix = " ltri"[dfi->dkind];
+      
+      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 (dump_flags_t dump_kind, FILE *dfile, source_location loc)
+{
+  if (dump_kind)
+    {
+      if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
+        fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc),
+                 LOCATION_LINE (loc), LOCATION_COLUMN (loc));
+      else if (current_function_decl)
+        fprintf (dfile, "%s:%d:%d: note: ",
+                 DECL_SOURCE_FILE (current_function_decl),
+                 DECL_SOURCE_LINE (current_function_decl),
+                 DECL_SOURCE_COLUMN (current_function_decl));
+    }
+}
+
+/* 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 (dump_flags_t dump_kind, dump_flags_t 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 (dump_flags_t dump_kind, source_location loc,
+		      dump_flags_t 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 (dump_flags_t dump_kind, dump_flags_t 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,
+		       dump_flags_t 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 (dump_flags_t 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 (dump_flags_t 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
+   -fopt-info stream. */
+
+int
+gcc::dump_manager::
+dump_start (int phase, dump_flags_t *flag_ptr)
+{
+  int count = 0;
+  char *name;
+  struct dump_file_info *dfi;
+  FILE *stream;
+  if (phase == TDI_none || !dump_phase_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 -fopt-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
+gcc::dump_manager::
+dump_finish (int phase)
+{
+  struct dump_file_info *dfi;
+
+  if (phase < 0)
+    return;
+  dfi = get_dump_file_info (phase);
+  if (dfi->pstream && (!dfi->pfilename
+                       || (strcmp ("stderr", dfi->pfilename) != 0
+                           && strcmp ("stdout", dfi->pfilename) != 0)))
+    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, dump_flags_t *flag_ptr)
+{
+  return g->get_dumps ()->dump_begin (phase, flag_ptr);
+}
+
+FILE *
+gcc::dump_manager::
+dump_begin (int phase, dump_flags_t *flag_ptr)
+{
+  char *name;
+  struct dump_file_info *dfi;
+  FILE *stream;
+
+  if (phase == TDI_none || !dump_phase_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
+gcc::dump_manager::
+dump_phase_enabled_p (int phase) const
+{
+  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 < m_extra_dump_files_in_use; i++)
+	if (m_extra_dump_files[i].pstate || m_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
+gcc::dump_manager::
+dump_initialized_p (int phase) const
+{
+  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)
+{
+  return g->get_dumps ()->dump_flag_name (phase);
+}
+
+const char *
+gcc::dump_manager::
+dump_flag_name (int phase) const
+{
+  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.  */
+
+int
+gcc::dump_manager::
+dump_enable_all (dump_kind dkind, dump_flags_t 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].dkind == dkind))
+        {
+          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 < m_extra_dump_files_in_use; i++)
+    {
+      if ((m_extra_dump_files[i].dkind == dkind))
+        {
+          const char *old_filename = m_extra_dump_files[i].pfilename;
+          m_extra_dump_files[i].pstate = -1;
+          m_extra_dump_files[i].pflags |= flags;
+          n++;
+          /* Override the existing filename.  */
+          if (filename)
+            {
+              m_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.  */
+              m_extra_dump_files[i].pstate = 1;
+            }
+          if (old_filename && filename != old_filename)
+            free (CONST_CAST (char *, old_filename));
+        }
+    }
+
+  return n;
+}
+
+/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
+   Enable dumps with FLAGS on FILENAME.  Return the number of enabled
+   dumps.  */
+
+int
+gcc::dump_manager::
+opt_info_enable_passes (int optgroup_flags, dump_flags_t 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].optgroup_flags & optgroup_flags))
+        {
+          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 < m_extra_dump_files_in_use; i++)
+    {
+      if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
+        {
+          const char *old_filename = m_extra_dump_files[i].alt_filename;
+          /* Since this file is shared among different passes, it
+             should be opened in append mode.  */
+          m_extra_dump_files[i].alt_state = 1;
+          m_extra_dump_files[i].alt_flags |= flags;
+          n++;
+          /* Override the existing filename.  */
+          if (filename)
+            m_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.  */
+
+int
+gcc::dump_manager::
+dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
+{
+  const char *option_value;
+  const char *ptr;
+  dump_flags_t 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->dkind, dfi->pflags, dfi->pfilename);
+
+  return 1;
+}
+
+int
+gcc::dump_manager::
+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 < m_extra_dump_files_in_use; i++)
+    any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false);
+
+  if (!any)
+    for (i = 0; i < m_extra_dump_files_in_use; i++)
+      any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true);
+
+
+  return any;
+}
+
+/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
+   and filename.  Return non-zero if it is a recognized switch.  */
+
+static int
+opt_info_switch_p_1 (const char *arg, dump_flags_t *flags, int *optgroup_flags,
+                     char **filename)
+{
+  const char *option_value;
+  const char *ptr;
+
+  option_value = arg;
+  ptr = option_value;
+
+  *filename = NULL;
+  *flags = 0;
+  *optgroup_flags = 0;
+
+  if (!ptr)
+    return 1;       /* Handle '-fopt-info' without any additional options.  */
+
+  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 = optinfo_verbosity_options; option_ptr->name;
+           option_ptr++)
+	if (strlen (option_ptr->name) == length
+	    && !memcmp (option_ptr->name, ptr, length))
+          {
+            *flags |= option_ptr->value;
+	    goto found;
+          }
+
+      for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
+	if (strlen (option_ptr->name) == length
+	    && !memcmp (option_ptr->name, ptr, length))
+          {
+            *optgroup_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, "unknown option %q.*s in %<-fopt-info-%s%>",
+                   length, ptr, arg);
+          return 0;
+        }
+    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)
+{
+  dump_flags_t flags;
+  int optgroup_flags;
+  char *filename;
+  static char *file_seen = NULL;
+  gcc::dump_manager *dumps = g->get_dumps ();
+
+  if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
+    return 0;
+
+  if (!filename)
+    filename = xstrdup ("stderr");
+
+  /* Bail out if a different filename has been specified.  */
+  if (file_seen && strcmp (file_seen, filename))
+    {
+      warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
+               arg);
+      return 1;
+    }
+
+  file_seen = xstrdup (filename);
+  if (!flags)
+    flags = MSG_OPTIMIZED_LOCATIONS;
+  if (!optgroup_flags)
+    optgroup_flags = OPTGROUP_ALL;
+
+  return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
+}
+
+/* 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);
+}
+
+/* Dump FUNCTION_DECL FN as tree dump PHASE.  */
+
+void
+dump_function (int phase, tree fn)
+{
+  FILE *stream;
+  dump_flags_t flags;
+
+  stream = dump_begin (phase, &flags);
+  if (stream)
+    {
+      dump_function_to_file (fn, stream, flags);
+      dump_end (phase, stream);
+    }
+}
+
+/* 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)
+{
+  gcc::dump_manager *dumps = g->get_dumps ();
+  int num_enabled =
+    dumps->dump_enable_all (DK_rtl, dump_flags_t (TDF_DETAILS) | TDF_BLOCKS,
+			    NULL);
+  return num_enabled > 0;
+}