re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / dumpfile.c
index 4ac427b273a6be03fd5b644b5fd39cada48b9707..d5f601f139de66d6a1d5020ab8e79867820aff9a 100644 (file)
@@ -1,5 +1,5 @@
 /* Dump infrastructure for optimizations and intermediate representation.
-   Copyright (C) 2012 Free Software Foundation, Inc.
+   Copyright (C) 2012-2015 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -22,8 +22,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "diagnostic-core.h"
 #include "dumpfile.h"
-#include "gimple-pretty-print.h"
+#include "alias.h"
+#include "symtab.h"
+#include "options.h"
 #include "tree.h"
+#include "gimple-pretty-print.h"
+#include "context.h"
 
 /* If non-NULL, return one past-the-end of the matching SUBPART of
    the WHOLE string.  */
@@ -32,46 +36,47 @@ along with GCC; see the file COPYING3.  If not see
 
 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_phase_enabled_p (int);
 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;
+int dump_flags;
+
 /* 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},
+  {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, false},
   {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
-   0, 0, 0, 0},
+   0, 0, 0, 0, 0, false},
+  {".type-inheritance", "ipa-type-inheritance", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
+   0, 0, 0, 0, 0, false},
   {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
-   0, 0, 0, 1},
+   0, 0, 0, 0, 1, false},
   {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
-   0, 0, 0, 2},
+   0, 0, 0, 0, 2, false},
   {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
-   0, 0, 0, 3},
+   0, 0, 0, 0, 3, false},
   {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
-   0, 0, 0, 4},
+   0, 0, 0, 0, 4, false},
   {".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},
-#define FIRST_AUTO_NUMBERED_DUMP 7
+   0, 0, 0, 0, 5, false},
+#define FIRST_AUTO_NUMBERED_DUMP 6
 
   {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
-   0, 0, 0, 0},
+   0, 0, 0, 0, 0, false},
   {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL,
-   0, 0, 0, 0},
+   0, 0, 0, 0, 0, false},
   {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
-   0, 0, 0, 0},
+   0, 0, 0, 0, 0, false},
 };
 
-/* 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
 {
@@ -105,53 +110,97 @@ static const struct dump_option_value_info dump_options[] =
   {"nouid", TDF_NOUID},
   {"enumerate_locals", TDF_ENUMERATE_LOCALS},
   {"scev", TDF_SCEV},
+  {"optimized", MSG_OPTIMIZED_LOCATIONS},
+  {"missed", MSG_MISSED_OPTIMIZATION},
+  {"note", MSG_NOTE},
+  {"optall", MSG_ALL},
   {"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.
+/* 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 opt_info_options[] =
+static const struct dump_option_value_info optinfo_verbosity_options[] =
 {
   {"optimized", MSG_OPTIMIZED_LOCATIONS},
   {"missed", MSG_MISSED_OPTIMIZATION},
   {"note", MSG_NOTE},
-  {"optall", (MSG_OPTIMIZED_LOCATIONS
-           | MSG_MISSED_OPTIMIZATION
-           | 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},
+  {"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,
-              int flags)
+              int flags, int optgroup_flags,
+              bool take_ownership)
 {
-  static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
-  int num = next_dump++;
+  int num = m_next_dump++;
 
-  size_t count = extra_dump_files_in_use++;
+  size_t count = m_extra_dump_files_in_use++;
 
-  if (count >= extra_dump_files_alloced)
+  if (count >= m_extra_dump_files_alloced)
     {
-      if (extra_dump_files_alloced == 0)
-       extra_dump_files_alloced = 32;
+      if (m_extra_dump_files_alloced == 0)
+       m_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);
+       m_extra_dump_files_alloced *= 2;
+      m_extra_dump_files = XRESIZEVEC (struct dump_file_info,
+                                      m_extra_dump_files,
+                                      m_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;
+  memset (&m_extra_dump_files[count], 0, sizeof (struct 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].pflags = flags;
+  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;
 }
@@ -160,30 +209,65 @@ dump_register (const char *suffix, const char *swtch, const char *glob,
 /* Return the dump_file_info for the given phase.  */
 
 struct dump_file_info *
-get_dump_file_info (int phase)
+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) >= extra_dump_files_in_use)
+  else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
     return NULL;
   else
-    return extra_dump_files + (phase - TDI_end);
+    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 *
-get_dump_file_name (int phase)
+gcc::dump_manager::
+get_dump_file_name (int phase) const
 {
-  char dump_id[10];
   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;
 
@@ -224,10 +308,10 @@ dump_open_alternate_stream (struct dump_file_info *dfi)
   if (dfi->alt_stream)
     return dfi->alt_stream;
 
-  stream = strcmp("stderr", dfi->alt_filename) == 0
+  stream = strcmp ("stderr", dfi->alt_filename) == 0
     ? stderr
-    : strcmp("stdout", dfi->alt_filename) == 0
-    ?  stdout
+    : strcmp ("stdout", dfi->alt_filename) == 0
+    ? stdout
     : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
 
   if (!stream)
@@ -243,15 +327,16 @@ dump_open_alternate_stream (struct dump_file_info *dfi)
 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: ",
+      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));
-     else
-        fprintf (dfile, "\n%d: ", LOCATION_LINE (loc));
+                 DECL_SOURCE_LINE (current_function_decl),
+                 DECL_SOURCE_COLUMN (current_function_decl));
     }
 }
 
@@ -370,10 +455,11 @@ dump_printf_loc (int dump_kind, source_location loc, const char *format, ...)
 /* 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. */
+   set dump_flags appropriately for both pass dump stream and
+   -fopt-info stream. */
 
 int
+gcc::dump_manager::
 dump_start (int phase, int *flag_ptr)
 {
   int count = 0;
@@ -387,10 +473,10 @@ dump_start (int phase, int *flag_ptr)
   name = get_dump_file_name (phase);
   if (name)
     {
-      stream = strcmp("stderr", name) == 0
+      stream = strcmp ("stderr", name) == 0
           ? stderr
-          : strcmp("stdout", name) == 0
-          ?  stdout
+          : strcmp ("stdout", name) == 0
+          ? stdout
           : fopen (name, dfi->pstate < 0 ? "w" : "a");
       if (!stream)
         error ("could not open dump file %qs: %m", name);
@@ -412,7 +498,7 @@ dump_start (int phase, int *flag_ptr)
       dfi->alt_stream = stream;
       count++;
       alt_dump_file = dfi->alt_stream;
-      /* Initialize current opt-info flags. */
+      /* Initialize current -fopt-info flags. */
       alt_flags = dfi->alt_flags;
     }
 
@@ -426,6 +512,7 @@ dump_start (int phase, int *flag_ptr)
    reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS.  */
 
 void
+gcc::dump_manager::
 dump_finish (int phase)
 {
   struct dump_file_info *dfi;
@@ -433,11 +520,13 @@ dump_finish (int phase)
   if (phase < 0)
     return;
   dfi = get_dump_file_info (phase);
-  if (dfi->pstream)
+  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)
+  if (dfi->alt_stream && strcmp ("stderr", dfi->alt_filename) != 0
+      && strcmp ("stdout", dfi->alt_filename) != 0)
     fclose (dfi->alt_stream);
 
   dfi->alt_stream = NULL;
@@ -456,6 +545,13 @@ dump_finish (int phase)
 
 FILE *
 dump_begin (int phase, int *flag_ptr)
+{
+  return g->get_dumps ()->dump_begin (phase, flag_ptr);
+}
+
+FILE *
+gcc::dump_manager::
+dump_begin (int phase, int *flag_ptr)
 {
   char *name;
   struct dump_file_info *dfi;
@@ -469,10 +565,10 @@ dump_begin (int phase, int *flag_ptr)
     return NULL;
   dfi = get_dump_file_info (phase);
 
-  stream = strcmp("stderr", name) == 0
+  stream = strcmp ("stderr", name) == 0
     ? stderr
-    : strcmp("stdout", name) == 0
-    ?  stdout
+    : strcmp ("stdout", name) == 0
+    ? stdout
     : fopen (name, dfi->pstate < 0 ? "w" : "a");
 
   if (!stream)
@@ -493,8 +589,9 @@ dump_begin (int phase, int *flag_ptr)
    If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
    any phase.  */
 
-static int
-dump_phase_enabled_p (int phase)
+int
+gcc::dump_manager::
+dump_phase_enabled_p (int phase) const
 {
   if (phase == TDI_tree_all)
     {
@@ -502,8 +599,8 @@ dump_phase_enabled_p (int phase)
       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)
+      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;
     }
@@ -514,18 +611,11 @@ dump_phase_enabled_p (int phase)
     }
 }
 
-/* Return true if any of the dumps are enabled, false otherwise. */
-
-inline bool
-dump_enabled_p (void)
-{
-  return (dump_file || alt_dump_file);
-}
-
 /* Returns nonzero if tree dump PHASE has been initialized.  */
 
 int
-dump_initialized_p (int phase)
+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;
@@ -535,6 +625,13 @@ dump_initialized_p (int 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;
@@ -553,7 +650,8 @@ dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
 /* Enable all tree dumps with FLAGS on FILENAME.  Return number of
    enabled tree dumps.  */
 
-static int
+int
+gcc::dump_manager::
 dump_enable_all (int flags, const char *filename)
 {
   int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
@@ -581,21 +679,21 @@ dump_enable_all (int flags, const char *filename)
         }
     }
 
-  for (i = 0; i < extra_dump_files_in_use; i++)
+  for (i = 0; i < m_extra_dump_files_in_use; i++)
     {
-      if ((extra_dump_files[i].pflags & ir_dump_type))
+      if ((m_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;
+          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)
             {
-              extra_dump_files[i].pfilename = xstrdup (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.  */
-              extra_dump_files[i].pstate = 1;
+              m_extra_dump_files[i].pstate = 1;
             }
           if (old_filename && filename != old_filename)
             free (CONST_CAST (char *, old_filename));
@@ -605,18 +703,20 @@ dump_enable_all (int flags, const char *filename)
   return n;
 }
 
-/* Enable opt-info dumps on all IR_DUMP_TYPE passes with FLAGS on
-   FILENAME.  Return the number of enabled dumps.  */
+/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
+   Enable dumps 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
+gcc::dump_manager::
+opt_info_enable_passes (int optgroup_flags, 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))
+      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
@@ -632,19 +732,19 @@ opt_info_enable_all (int ir_dump_type, int flags, const char *filename)
         }
     }
 
-  for (i = 0; i < extra_dump_files_in_use; i++)
+  for (i = 0; i < m_extra_dump_files_in_use; i++)
     {
-      if ((extra_dump_files[i].pflags & ir_dump_type))
+      if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
         {
-          const char *old_filename = extra_dump_files[i].alt_filename;
+          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.  */
-          extra_dump_files[i].alt_state = 1;
-          extra_dump_files[i].alt_flags |= flags;
+          m_extra_dump_files[i].alt_state = 1;
+          m_extra_dump_files[i].alt_flags |= flags;
           n++;
           /* Override the existing filename.  */
           if (filename)
-            extra_dump_files[i].alt_filename = xstrdup (filename);
+            m_extra_dump_files[i].alt_filename = xstrdup (filename);
           if (old_filename && filename != old_filename)
             free (CONST_CAST (char *, old_filename));
         }
@@ -656,7 +756,8 @@ opt_info_enable_all (int ir_dump_type, int flags, const char *filename)
 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
    relevant details in the dump_files array.  */
 
-static int
+int
+gcc::dump_manager::
 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
 {
   const char *option_value;
@@ -731,6 +832,7 @@ dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
 }
 
 int
+gcc::dump_manager::
 dump_switch_p (const char *arg)
 {
   size_t i;
@@ -744,22 +846,23 @@ dump_switch_p (const char *arg)
     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);
+  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 < extra_dump_files_in_use; i++)
-      any |= dump_switch_p_1 (arg, &extra_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], true);
 
 
   return any;
 }
 
-/* Parse ARG as a -fopt-info switch and store flags and filename.
-   Return non-zero if it is a recognized switch.  */
+/* 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, int *flags, char **filename)
+opt_info_switch_p_1 (const char *arg, int *flags, int *optgroup_flags,
+                     char **filename)
 {
   const char *option_value;
   const char *ptr;
@@ -769,9 +872,10 @@ opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
 
   *filename = NULL;
   *flags = 0;
+  *optgroup_flags = 0;
 
   if (!ptr)
-    return 1;
+    return 1;       /* Handle '-fopt-info' without any additional options.  */
 
   while (*ptr)
     {
@@ -792,7 +896,8 @@ opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
        end_ptr = ptr + strlen (ptr);
       length = end_ptr - ptr;
 
-      for (option_ptr = opt_info_options; option_ptr->name; option_ptr++)
+      for (option_ptr = optinfo_verbosity_options; option_ptr->name;
+           option_ptr++)
        if (strlen (option_ptr->name) == length
            && !memcmp (option_ptr->name, ptr, length))
           {
@@ -800,6 +905,14 @@ opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
            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
@@ -808,8 +921,11 @@ opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
           break;
         }
       else
-        warning (0, "ignoring unknown option %q.*s in %<-fopt-info=%s%>",
-                 length, ptr, arg);
+        {
+          warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
+                   length, ptr, arg);
+          return 0;
+        }
     found:;
       ptr = end_ptr;
     }
@@ -824,26 +940,32 @@ int
 opt_info_switch_p (const char *arg)
 {
   int flags;
+  int optgroup_flags;
   char *filename;
+  static char *file_seen = NULL;
+  gcc::dump_manager *dumps = g->get_dumps ();
 
-  opt_info_switch_p_1 (arg, &flags, &filename);
+  if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
+    return 0;
 
   if (!filename)
     filename = xstrdup ("stderr");
-  if (!flags)
-    flags = MSG_ALL;
 
-  return opt_info_enable_all ((TDF_TREE | TDF_RTL | TDF_IPA), flags, filename);
-}
+  /* 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;
+    }
 
-/* Return true if any dumps are enabled for the given MSG_TYPE, false
-   otherwise.  */
+  file_seen = xstrdup (filename);
+  if (!flags)
+    flags = MSG_OPTIMIZED_LOCATIONS;
+  if (!optgroup_flags)
+    optgroup_flags = OPTGROUP_ALL;
 
-bool
-dump_kind_p (int msg_type)
-{
-  return (dump_file && (msg_type & pflags))
-    || (alt_dump_file && (msg_type & alt_flags));
+  return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
 }
 
 /* Print basic block on the dump streams.  */
@@ -871,5 +993,8 @@ print_combine_total_stats (void)
 bool
 enable_rtl_dump_file (void)
 {
-  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
+  gcc::dump_manager *dumps = g->get_dumps ();
+  int num_enabled =
+    dumps->dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL);
+  return num_enabled > 0;
 }