diff mbox

Add option for dumping to stderr (issue6190057)

Message ID 20120509064637.22949A2081@nabu.mtv.corp.google.com
State New
Headers show

Commit Message

Sharad Singhai May 9, 2012, 6:46 a.m. UTC
In response to comments, I have updated the patch to support dumps in
user provided files via the option -fdump-xxx=<filename>. The
filenames stdout/stderr are treated specially, and are considered
standard streams.

Also updated documentation and a testcase. Okay for trunk?

Thanks,
Sharad

2012-05-08   Sharad Singhai  <singhai@google.com>

	* doc/invoke.texi: Add documentation for new option.
	* tree-dump.c (dump_stream_p): New function.
	(dump_files): Update for new field.
	(dump_switch_p_1): Handle user provided filenames.
	(dump_begin): Likewise.
	(get_dump_file_name): Likewise.
	(dump_enable_all): Add new parameter USER_FILENAME.
	All callers updated.
	(dump_end): Remove attribute.
	* tree-pass.h (enum tree_dump_index): Add new constant.
	(struct dump_file_info): Add new field USER_FILENAME.
	* testsuite/g++.dg/other/dump-userfile-1.C: New test.


--
This patch is available for review at http://codereview.appspot.com/6190057

Comments

Andrew Pinski May 9, 2012, 6:51 a.m. UTC | #1
On Tue, May 8, 2012 at 11:46 PM, Sharad Singhai <singhai@google.com> wrote:
> In response to comments, I have updated the patch to support dumps in
> user provided files via the option -fdump-xxx=<filename>. The
> filenames stdout/stderr are treated specially, and are considered
> standard streams.

I think - should also be treated as special (or maybe the only one
which should be treated as special).

Thanks,
Andrew Pinski

>
> Also updated documentation and a testcase. Okay for trunk?
>
> Thanks,
> Sharad
>
> 2012-05-08   Sharad Singhai  <singhai@google.com>
>
>        * doc/invoke.texi: Add documentation for new option.
>        * tree-dump.c (dump_stream_p): New function.
>        (dump_files): Update for new field.
>        (dump_switch_p_1): Handle user provided filenames.
>        (dump_begin): Likewise.
>        (get_dump_file_name): Likewise.
>        (dump_enable_all): Add new parameter USER_FILENAME.
>        All callers updated.
>        (dump_end): Remove attribute.
>        * tree-pass.h (enum tree_dump_index): Add new constant.
>        (struct dump_file_info): Add new field USER_FILENAME.
>        * testsuite/g++.dg/other/dump-userfile-1.C: New test.
>
> Index: doc/invoke.texi
> ===================================================================
> --- doc/invoke.texi     (revision 187265)
> +++ doc/invoke.texi     (working copy)
> @@ -5322,20 +5322,24 @@ Here are some examples showing uses of these optio
>
>  @item -d@var{letters}
>  @itemx -fdump-rtl-@var{pass}
> +@itemx -fdump-rtl-@var{pass}=@var{filename}
>  @opindex d
>  Says to make debugging dumps during compilation at times specified by
>  @var{letters}.  This is used for debugging the RTL-based passes of the
>  compiler.  The file names for most of the dumps are made by appending
>  a pass number and a word to the @var{dumpname}, and the files are
> -created in the directory of the output file.  Note that the pass
> -number is computed statically as passes get registered into the pass
> -manager.  Thus the numbering is not related to the dynamic order of
> -execution of passes.  In particular, a pass installed by a plugin
> -could have a number over 200 even if it executed quite early.
> -@var{dumpname} is generated from the name of the output file, if
> -explicitly specified and it is not an executable, otherwise it is the
> -basename of the source file. These switches may have different effects
> -when @option{-E} is used for preprocessing.
> +created in the directory of the output file. If the
> +@option{=@var{filename}} is appended to the longer form of the dump
> +option then the dump is done on that file instead of numbered
> +files. The filenames stdout and stderr are treated specially. Note
> +that the pass number is computed statically as passes get registered
> +into the pass manager.  Thus the numbering is not related to the
> +dynamic order of execution of passes.  In particular, a pass installed
> +by a plugin could have a number over 200 even if it executed quite
> +early.  @var{dumpname} is generated from the name of the output file,
> +if explicitly specified and it is not an executable, otherwise it is
> +the basename of the source file. These switches may have different
> +effects when @option{-E} is used for preprocessing.
>
>  Debug dumps can be enabled with a @option{-fdump-rtl} switch or some
>  @option{-d} option @var{letters}.  Here are the possible
> @@ -5599,6 +5603,10 @@ These dumps are defined but always produce empty f
>  @opindex fdump-rtl-all
>  Produce all the dumps listed above.
>
> +@item -fdump-rtl-all=stderr
> +@opindex fdump-rtl-all=stderr
> +Produce all RTL dumps on stderr.
> +
>  @item -dA
>  @opindex dA
>  Annotate the assembler output with miscellaneous debugging information.
> @@ -5719,15 +5727,19 @@ counters for each function compiled.
>
>  @item -fdump-tree-@var{switch}
>  @itemx -fdump-tree-@var{switch}-@var{options}
> +@itemx -fdump-tree-@var{switch}-@var{options}=@var{filename}
>  @opindex fdump-tree
>  Control the dumping at various stages of processing the intermediate
>  language tree to a file.  The file name is generated by appending a
>  switch specific suffix to the source file name, and the file is
> -created in the same directory as the output file.  If the
> -@samp{-@var{options}} form is used, @var{options} is a list of
> -@samp{-} separated options which control the details of the dump.  Not
> -all options are applicable to all dumps; those that are not
> -meaningful are ignored.  The following options are available
> +created in the same directory as the output file. In case of
> +@option{=@var{filename}}, the dump output is on the given file. Note
> +that the filenames stdout and stderr are treated specially and dumps
> +are done on standard streams. If the @samp{-@var{options}} form is
> +used, @var{options} is a list of @samp{-} separated options which
> +control the details or location of the dump.  Not all options are
> +applicable to all dumps; those that are not meaningful are ignored.
> +The following options are available
>
>  @table @samp
>  @item address
> @@ -5765,9 +5777,56 @@ Enable showing the tree dump for each statement.
>  Enable showing the EH region number holding each statement.
>  @item scev
>  Enable showing scalar evolution analysis details.
> +@item slim
> +Inhibit dumping of members of a scope or body of a function merely
> +because that scope has been reached.  Only dump such items when they
> +are directly reachable by some other path.  When dumping pretty-printed
> +trees, this option inhibits dumping the bodies of control structures.
> +@item =@var{filename}
> +Instead of using an auto generated name for a dump file, use the
> +provided name. For example:
> +
> +@smallexample
> +gcc -O2 -fdump-tree-pre=foobar.dump
> +@end smallexample
> +
> +produces PRE dump in a file named foobar.dump. Similarly
> +
> +@smallexample
> +gcc -O2 -fdump-tree-all=all.dump
> +@end smallexample
> +
> +produces all tree dumps in a file named all.dump.
> +
> +Note that stdout and stderr are treated specially, and the dumps are
> +done on standard streams. In case of any conflicts, the user provided
> +filename takes precedence. For example:
> +
> +@smallexample
> +gcc -O2 -fdump-tree-pre=stderr -fdump-tree-pre ...
> +gcc -O2 -fdump-tree-pre -fdump-tree-pre=stderr ...
> +@end smallexample
> +
> +Both invocations produce the PRE dump on stderr. Similarly, for the
> +following
> +
> +@smallexample
> +gcc -O2 -fdump-tree-all=stderr -fdump-tree-pre ...
> +@end smallexample
> +
> +All the dumps are output on stderr. In the following example,
> +
> +@smallexample
> +gcc -fdump-tree-all -fdump-tree-pre=stderr ...
> +@end smallexample
> +
> +all the dumps are written into named files except the PRE dump, which
> +is output on stderr, because @option{-fdump-tree-pre=stderr} takes
> +precedence.
> +
>  @item all
> -Turn on all options, except @option{raw}, @option{slim}, @option{verbose}
> -and @option{lineno}.
> +Turn on all options, except @option{raw}, @option{slim}, @option{verbose},
> +@option{lineno}.
>  @end table
>
>  The following tree dumps are possible:
> @@ -5913,6 +5972,10 @@ is made by appending @file{.vrp} to the source fil
>  @item all
>  @opindex fdump-tree-all
>  Enable all the available tree dumps with the flags provided in this option.
> +
> +@item all=stderr
> +@opindex fdump-tree-all=stderr
> +Enable all the available tree dumps on the stderr.
>  @end table
>
>  @item -ftree-vectorizer-verbose=@var{n}
> Index: tree-dump.c
> ===================================================================
> --- tree-dump.c (revision 187265)
> +++ tree-dump.c (working copy)
> @@ -773,20 +773,20 @@ dump_node (const_tree t, int flags, FILE *stream)
>    tree_dump_index enumeration in tree-pass.h.  */
>  static struct dump_file_info dump_files[TDI_end] =
>  {
> -  {NULL, NULL, NULL, 0, 0, 0},
> -  {".cgraph", "ipa-cgraph", NULL, TDF_IPA, 0,  0},
> -  {".tu", "translation-unit", NULL, TDF_TREE, 0, 1},
> -  {".class", "class-hierarchy", NULL, TDF_TREE, 0, 2},
> -  {".original", "tree-original", NULL, TDF_TREE, 0, 3},
> -  {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 4},
> -  {".nested", "tree-nested", NULL, TDF_TREE, 0, 5},
> -  {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6},
> -  {".ads", "ada-spec", NULL, 0, 0, 7},
> +  {NULL, NULL, NULL, NULL, 0, 0, 0},
> +  {".cgraph", "ipa-cgraph", NULL, NULL, TDF_IPA, 0,  0},
> +  {".tu", "translation-unit", NULL, NULL, TDF_TREE, 0, 1},
> +  {".class", "class-hierarchy", NULL, NULL, TDF_TREE, 0, 2},
> +  {".original", "tree-original", NULL, NULL, TDF_TREE, 0, 3},
> +  {".gimple", "tree-gimple", NULL, NULL, TDF_TREE, 0, 4},
> +  {".nested", "tree-nested", NULL, NULL, TDF_TREE, 0, 5},
> +  {".vcg", "tree-vcg", NULL, NULL, TDF_TREE, 0, 6},
> +  {".ads", "ada-spec", NULL, NULL, 0, 0, 7},
>  #define FIRST_AUTO_NUMBERED_DUMP 8
>
> -  {NULL, "tree-all", NULL, TDF_TREE, 0, 0},
> -  {NULL, "rtl-all", NULL, TDF_RTL, 0, 0},
> -  {NULL, "ipa-all", NULL, TDF_IPA, 0, 0},
> +  {NULL, "tree-all", NULL, NULL, TDF_TREE, 0, 0},
> +  {NULL, "rtl-all", NULL, NULL, TDF_RTL, 0, 0},
> +  {NULL, "ipa-all", NULL, NULL, TDF_IPA, 0, 0},
>  };
>
>  /* Dynamically registered tree dump files and switches.  */
> @@ -802,7 +802,7 @@ struct dump_option_value_info
>  };
>
>  /* Table of dump options. This must be consistent with the TDF_* flags
> -   in tree.h */
> +   in tree-pass.h */
>  static const struct dump_option_value_info dump_options[] =
>  {
>   {"address", TDF_ADDRESS},
> @@ -892,6 +892,9 @@ get_dump_file_name (int phase)
>   if (dfi->state == 0)
>     return NULL;
>
> +  if (dfi->user_filename)
> +    return xstrdup (dfi->user_filename);
> +
>   if (dfi->num < 0)
>     dump_id[0] = '\0';
>   else
> @@ -911,6 +914,19 @@ get_dump_file_name (int phase)
>   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
>  }
>
> +/* Return non-zero iff the USER_FILENAME corresponds to stdout or
> +   stderr stream.  */
> +
> +static int
> +dump_stream_p (const char *user_filename)
> +{
> +  if (user_filename)
> +    return !strncmp ("stderr", user_filename, 6) ||
> +      !strncmp ("stdout", user_filename, 6);
> +  else
> +    return 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.
> @@ -926,14 +942,28 @@ dump_begin (int phase, int *flag_ptr)
>   if (phase == TDI_none || !dump_enabled_p (phase))
>     return NULL;
>
> -  name = get_dump_file_name (phase);
>   dfi = get_dump_file_info (phase);
> -  stream = fopen (name, dfi->state < 0 ? "w" : "a");
> -  if (!stream)
> -    error ("could not open dump file %qs: %m", name);
> +  if (dump_stream_p (dfi->user_filename))
> +    {
> +      if (!strncmp ("stderr", dfi->user_filename, 6))
> +        stream = stderr;
> +      else
> +        if (!strncmp ("stdout", dfi->user_filename, 6))
> +          stream = stdout;
> +        else
> +          error ("unknown stream: %qs: %m", dfi->user_filename);
> +      dfi->state = 1;
> +    }
>   else
> -    dfi->state = 1;
> -  free (name);
> +    {
> +      name = get_dump_file_name (phase);
> +      stream = fopen (name, dfi->state < 0 ? "w" : "a");
> +      if (!stream)
> +        error ("could not open dump file %qs: %m", name);
> +      else
> +        dfi->state = 1;
> +      free (name);
> +    }
>
>   if (flag_ptr)
>     *flag_ptr = dfi->flags;
> @@ -987,35 +1017,45 @@ dump_flag_name (int phase)
>    dump_begin.  */
>
>  void
> -dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
> +dump_end (int phase, FILE *stream)
>  {
> -  fclose (stream);
> +  struct dump_file_info *dfi = get_dump_file_info (phase);
> +  if (!dump_stream_p (dfi->user_filename))
> +    fclose (stream);
>  }
>
>  /* Enable all tree dumps.  Return number of enabled tree dumps.  */
>
>  static int
> -dump_enable_all (int flags)
> +dump_enable_all (int flags, const char *user_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].flags & ir_dump_type))
> -      {
> -        dump_files[i].state = -1;
> -        dump_files[i].flags |= flags;
> -        n++;
> -      }
> +    {
> +      if ((dump_files[i].flags & ir_dump_type))
> +        {
> +          dump_files[i].state = -1;
> +          dump_files[i].flags |= flags;
> +          n++;
> +        }
> +      if (user_filename)
> +        dump_files[i].user_filename = user_filename;
> +    }
>
>   for (i = 0; i < extra_dump_files_in_use; i++)
> -    if ((extra_dump_files[i].flags & ir_dump_type))
> -      {
> -        extra_dump_files[i].state = -1;
> -        extra_dump_files[i].flags |= flags;
> -       n++;
> -      }
> +    {
> +      if ((extra_dump_files[i].flags & ir_dump_type))
> +        {
> +          extra_dump_files[i].state = -1;
> +          extra_dump_files[i].flags |= flags;
> +          n++;
> +        }
> +      if (user_filename)
> +        extra_dump_files[i].user_filename = user_filename;
> +    }
>
>   return n;
>  }
> @@ -1037,7 +1077,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>   if (!option_value)
>     return 0;
>
> -  if (*option_value && *option_value != '-')
> +  if (*option_value && *option_value != '-' && *option_value != '=')
>     return 0;
>
>   ptr = option_value;
> @@ -1052,17 +1092,30 @@ dump_switch_p_1 (const char *arg, struct dump_file
>       while (*ptr == '-')
>        ptr++;
>       end_ptr = strchr (ptr, '-');
> +
>       if (!end_ptr)
>        end_ptr = ptr + strlen (ptr);
>       length = end_ptr - ptr;
>
> +      if (*ptr == '=')
> +        {
> +          /* Interpret rest of the argument as a dump filename.  The
> +             user provided filename overrides generated dump names as
> +             well as other command line filenames.  */
> +          flags |= TDF_USER_FILENAME;
> +          if (dfi->user_filename)
> +            free (dfi->user_filename);
> +          dfi->user_filename = xstrdup (ptr + 1);
> +          break;
> +        }
> +
>       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;
> +          {
> +            flags |= option_ptr->value;
>            goto found;
> -         }
> +          }
>       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
>               length, ptr, dfi->swtch);
>     found:;
> @@ -1075,7 +1128,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
>      known dumps.  */
>   if (dfi->suffix == NULL)
> -    dump_enable_all (dfi->flags);
> +    dump_enable_all (dfi->flags, dfi->user_filename);
>
>   return 1;
>  }
> @@ -1124,5 +1177,5 @@ dump_function (int phase, tree fn)
>  bool
>  enable_rtl_dump_file (void)
>  {
> -  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS) > 0;
> +  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
>  }
> Index: tree-pass.h
> ===================================================================
> --- tree-pass.h (revision 187265)
> +++ tree-pass.h (working copy)
> @@ -84,8 +84,9 @@ enum tree_dump_index
>  #define TDF_ENUMERATE_LOCALS (1 << 22) /* Enumerate locals by uid.  */
>  #define TDF_CSELIB     (1 << 23)       /* Dump cselib details.  */
>  #define TDF_SCEV       (1 << 24)       /* Dump SCEV details.  */
> +#define TDF_USER_FILENAME    (1 << 25) /* Dump on user provided filename,
> +                                           instead of constructing one. */
>
> -
>  /* In tree-dump.c */
>
>  extern char *get_dump_file_name (int);
> @@ -222,6 +223,8 @@ struct dump_file_info
>   const char *suffix;           /* suffix to give output file.  */
>   const char *swtch;            /* command line switch */
>   const char *glob;             /* command line glob  */
> +  const char *user_filename;    /* user provided filename instead of making
> +                                   up one using dump_base_name + suffix.  */
>   int flags;                    /* user flags */
>   int state;                    /* state of play */
>   int num;                      /* dump file number */
> Index: testsuite/g++.dg/other/dump-userfile-1.C
> ===================================================================
> --- testsuite/g++.dg/other/dump-userfile-1.C    (revision 0)
> +++ testsuite/g++.dg/other/dump-userfile-1.C    (revision 0)
> @@ -0,0 +1,11 @@
> +// Test that the dump to a user-defined file works correctly.
> +/* { dg-options "-O2 -fdump-tree-original=foobar.dump" } */
> +
> +void test (int *b, int *e, int stride)
> +  {
> +    for (int *p = b; p != e; p += stride)
> +      *p = 1;
> +  }
> +
> +/* { dg-final { scan-file foobar.dump ";; Function void test" } } */
> +/* { dg-final { remove-build-file "foobar.dump" } } */
>
> --
> This patch is available for review at http://codereview.appspot.com/6190057
Gabriel Dos Reis May 9, 2012, 6:55 a.m. UTC | #2
On Wed, May 9, 2012 at 1:51 AM, Andrew Pinski <pinskia@gmail.com> wrote:
> On Tue, May 8, 2012 at 11:46 PM, Sharad Singhai <singhai@google.com> wrote:
>> In response to comments, I have updated the patch to support dumps in
>> user provided files via the option -fdump-xxx=<filename>. The
>> filenames stdout/stderr are treated specially, and are considered
>> standard streams.
>
> I think - should also be treated as special (or maybe the only one
> which should be treated as special).

He originally wanted only "stderr", so treating "-" only specially
would not be in
the line with his original goal.  "-" is equivalent to "stdout", so it
is not like
we don't have the functionally with his revised patch.

>
> Thanks,
> Andrew Pinski
>
>>
>> Also updated documentation and a testcase. Okay for trunk?
>>
>> Thanks,
>> Sharad
>>
>> 2012-05-08   Sharad Singhai  <singhai@google.com>
>>
>>        * doc/invoke.texi: Add documentation for new option.
>>        * tree-dump.c (dump_stream_p): New function.
>>        (dump_files): Update for new field.
>>        (dump_switch_p_1): Handle user provided filenames.
>>        (dump_begin): Likewise.
>>        (get_dump_file_name): Likewise.
>>        (dump_enable_all): Add new parameter USER_FILENAME.
>>        All callers updated.
>>        (dump_end): Remove attribute.
>>        * tree-pass.h (enum tree_dump_index): Add new constant.
>>        (struct dump_file_info): Add new field USER_FILENAME.
>>        * testsuite/g++.dg/other/dump-userfile-1.C: New test.
>>
>> Index: doc/invoke.texi
>> ===================================================================
>> --- doc/invoke.texi     (revision 187265)
>> +++ doc/invoke.texi     (working copy)
>> @@ -5322,20 +5322,24 @@ Here are some examples showing uses of these optio
>>
>>  @item -d@var{letters}
>>  @itemx -fdump-rtl-@var{pass}
>> +@itemx -fdump-rtl-@var{pass}=@var{filename}
>>  @opindex d
>>  Says to make debugging dumps during compilation at times specified by
>>  @var{letters}.  This is used for debugging the RTL-based passes of the
>>  compiler.  The file names for most of the dumps are made by appending
>>  a pass number and a word to the @var{dumpname}, and the files are
>> -created in the directory of the output file.  Note that the pass
>> -number is computed statically as passes get registered into the pass
>> -manager.  Thus the numbering is not related to the dynamic order of
>> -execution of passes.  In particular, a pass installed by a plugin
>> -could have a number over 200 even if it executed quite early.
>> -@var{dumpname} is generated from the name of the output file, if
>> -explicitly specified and it is not an executable, otherwise it is the
>> -basename of the source file. These switches may have different effects
>> -when @option{-E} is used for preprocessing.
>> +created in the directory of the output file. If the
>> +@option{=@var{filename}} is appended to the longer form of the dump
>> +option then the dump is done on that file instead of numbered
>> +files. The filenames stdout and stderr are treated specially. Note
>> +that the pass number is computed statically as passes get registered
>> +into the pass manager.  Thus the numbering is not related to the
>> +dynamic order of execution of passes.  In particular, a pass installed
>> +by a plugin could have a number over 200 even if it executed quite
>> +early.  @var{dumpname} is generated from the name of the output file,
>> +if explicitly specified and it is not an executable, otherwise it is
>> +the basename of the source file. These switches may have different
>> +effects when @option{-E} is used for preprocessing.
>>
>>  Debug dumps can be enabled with a @option{-fdump-rtl} switch or some
>>  @option{-d} option @var{letters}.  Here are the possible
>> @@ -5599,6 +5603,10 @@ These dumps are defined but always produce empty f
>>  @opindex fdump-rtl-all
>>  Produce all the dumps listed above.
>>
>> +@item -fdump-rtl-all=stderr
>> +@opindex fdump-rtl-all=stderr
>> +Produce all RTL dumps on stderr.
>> +
>>  @item -dA
>>  @opindex dA
>>  Annotate the assembler output with miscellaneous debugging information.
>> @@ -5719,15 +5727,19 @@ counters for each function compiled.
>>
>>  @item -fdump-tree-@var{switch}
>>  @itemx -fdump-tree-@var{switch}-@var{options}
>> +@itemx -fdump-tree-@var{switch}-@var{options}=@var{filename}
>>  @opindex fdump-tree
>>  Control the dumping at various stages of processing the intermediate
>>  language tree to a file.  The file name is generated by appending a
>>  switch specific suffix to the source file name, and the file is
>> -created in the same directory as the output file.  If the
>> -@samp{-@var{options}} form is used, @var{options} is a list of
>> -@samp{-} separated options which control the details of the dump.  Not
>> -all options are applicable to all dumps; those that are not
>> -meaningful are ignored.  The following options are available
>> +created in the same directory as the output file. In case of
>> +@option{=@var{filename}}, the dump output is on the given file. Note
>> +that the filenames stdout and stderr are treated specially and dumps
>> +are done on standard streams. If the @samp{-@var{options}} form is
>> +used, @var{options} is a list of @samp{-} separated options which
>> +control the details or location of the dump.  Not all options are
>> +applicable to all dumps; those that are not meaningful are ignored.
>> +The following options are available
>>
>>  @table @samp
>>  @item address
>> @@ -5765,9 +5777,56 @@ Enable showing the tree dump for each statement.
>>  Enable showing the EH region number holding each statement.
>>  @item scev
>>  Enable showing scalar evolution analysis details.
>> +@item slim
>> +Inhibit dumping of members of a scope or body of a function merely
>> +because that scope has been reached.  Only dump such items when they
>> +are directly reachable by some other path.  When dumping pretty-printed
>> +trees, this option inhibits dumping the bodies of control structures.
>> +@item =@var{filename}
>> +Instead of using an auto generated name for a dump file, use the
>> +provided name. For example:
>> +
>> +@smallexample
>> +gcc -O2 -fdump-tree-pre=foobar.dump
>> +@end smallexample
>> +
>> +produces PRE dump in a file named foobar.dump. Similarly
>> +
>> +@smallexample
>> +gcc -O2 -fdump-tree-all=all.dump
>> +@end smallexample
>> +
>> +produces all tree dumps in a file named all.dump.
>> +
>> +Note that stdout and stderr are treated specially, and the dumps are
>> +done on standard streams. In case of any conflicts, the user provided
>> +filename takes precedence. For example:
>> +
>> +@smallexample
>> +gcc -O2 -fdump-tree-pre=stderr -fdump-tree-pre ...
>> +gcc -O2 -fdump-tree-pre -fdump-tree-pre=stderr ...
>> +@end smallexample
>> +
>> +Both invocations produce the PRE dump on stderr. Similarly, for the
>> +following
>> +
>> +@smallexample
>> +gcc -O2 -fdump-tree-all=stderr -fdump-tree-pre ...
>> +@end smallexample
>> +
>> +All the dumps are output on stderr. In the following example,
>> +
>> +@smallexample
>> +gcc -fdump-tree-all -fdump-tree-pre=stderr ...
>> +@end smallexample
>> +
>> +all the dumps are written into named files except the PRE dump, which
>> +is output on stderr, because @option{-fdump-tree-pre=stderr} takes
>> +precedence.
>> +
>>  @item all
>> -Turn on all options, except @option{raw}, @option{slim}, @option{verbose}
>> -and @option{lineno}.
>> +Turn on all options, except @option{raw}, @option{slim}, @option{verbose},
>> +@option{lineno}.
>>  @end table
>>
>>  The following tree dumps are possible:
>> @@ -5913,6 +5972,10 @@ is made by appending @file{.vrp} to the source fil
>>  @item all
>>  @opindex fdump-tree-all
>>  Enable all the available tree dumps with the flags provided in this option.
>> +
>> +@item all=stderr
>> +@opindex fdump-tree-all=stderr
>> +Enable all the available tree dumps on the stderr.
>>  @end table
>>
>>  @item -ftree-vectorizer-verbose=@var{n}
>> Index: tree-dump.c
>> ===================================================================
>> --- tree-dump.c (revision 187265)
>> +++ tree-dump.c (working copy)
>> @@ -773,20 +773,20 @@ dump_node (const_tree t, int flags, FILE *stream)
>>    tree_dump_index enumeration in tree-pass.h.  */
>>  static struct dump_file_info dump_files[TDI_end] =
>>  {
>> -  {NULL, NULL, NULL, 0, 0, 0},
>> -  {".cgraph", "ipa-cgraph", NULL, TDF_IPA, 0,  0},
>> -  {".tu", "translation-unit", NULL, TDF_TREE, 0, 1},
>> -  {".class", "class-hierarchy", NULL, TDF_TREE, 0, 2},
>> -  {".original", "tree-original", NULL, TDF_TREE, 0, 3},
>> -  {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 4},
>> -  {".nested", "tree-nested", NULL, TDF_TREE, 0, 5},
>> -  {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6},
>> -  {".ads", "ada-spec", NULL, 0, 0, 7},
>> +  {NULL, NULL, NULL, NULL, 0, 0, 0},
>> +  {".cgraph", "ipa-cgraph", NULL, NULL, TDF_IPA, 0,  0},
>> +  {".tu", "translation-unit", NULL, NULL, TDF_TREE, 0, 1},
>> +  {".class", "class-hierarchy", NULL, NULL, TDF_TREE, 0, 2},
>> +  {".original", "tree-original", NULL, NULL, TDF_TREE, 0, 3},
>> +  {".gimple", "tree-gimple", NULL, NULL, TDF_TREE, 0, 4},
>> +  {".nested", "tree-nested", NULL, NULL, TDF_TREE, 0, 5},
>> +  {".vcg", "tree-vcg", NULL, NULL, TDF_TREE, 0, 6},
>> +  {".ads", "ada-spec", NULL, NULL, 0, 0, 7},
>>  #define FIRST_AUTO_NUMBERED_DUMP 8
>>
>> -  {NULL, "tree-all", NULL, TDF_TREE, 0, 0},
>> -  {NULL, "rtl-all", NULL, TDF_RTL, 0, 0},
>> -  {NULL, "ipa-all", NULL, TDF_IPA, 0, 0},
>> +  {NULL, "tree-all", NULL, NULL, TDF_TREE, 0, 0},
>> +  {NULL, "rtl-all", NULL, NULL, TDF_RTL, 0, 0},
>> +  {NULL, "ipa-all", NULL, NULL, TDF_IPA, 0, 0},
>>  };
>>
>>  /* Dynamically registered tree dump files and switches.  */
>> @@ -802,7 +802,7 @@ struct dump_option_value_info
>>  };
>>
>>  /* Table of dump options. This must be consistent with the TDF_* flags
>> -   in tree.h */
>> +   in tree-pass.h */
>>  static const struct dump_option_value_info dump_options[] =
>>  {
>>   {"address", TDF_ADDRESS},
>> @@ -892,6 +892,9 @@ get_dump_file_name (int phase)
>>   if (dfi->state == 0)
>>     return NULL;
>>
>> +  if (dfi->user_filename)
>> +    return xstrdup (dfi->user_filename);
>> +
>>   if (dfi->num < 0)
>>     dump_id[0] = '\0';
>>   else
>> @@ -911,6 +914,19 @@ get_dump_file_name (int phase)
>>   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
>>  }
>>
>> +/* Return non-zero iff the USER_FILENAME corresponds to stdout or
>> +   stderr stream.  */
>> +
>> +static int
>> +dump_stream_p (const char *user_filename)
>> +{
>> +  if (user_filename)
>> +    return !strncmp ("stderr", user_filename, 6) ||
>> +      !strncmp ("stdout", user_filename, 6);
>> +  else
>> +    return 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.
>> @@ -926,14 +942,28 @@ dump_begin (int phase, int *flag_ptr)
>>   if (phase == TDI_none || !dump_enabled_p (phase))
>>     return NULL;
>>
>> -  name = get_dump_file_name (phase);
>>   dfi = get_dump_file_info (phase);
>> -  stream = fopen (name, dfi->state < 0 ? "w" : "a");
>> -  if (!stream)
>> -    error ("could not open dump file %qs: %m", name);
>> +  if (dump_stream_p (dfi->user_filename))
>> +    {
>> +      if (!strncmp ("stderr", dfi->user_filename, 6))
>> +        stream = stderr;
>> +      else
>> +        if (!strncmp ("stdout", dfi->user_filename, 6))
>> +          stream = stdout;
>> +        else
>> +          error ("unknown stream: %qs: %m", dfi->user_filename);
>> +      dfi->state = 1;
>> +    }
>>   else
>> -    dfi->state = 1;
>> -  free (name);
>> +    {
>> +      name = get_dump_file_name (phase);
>> +      stream = fopen (name, dfi->state < 0 ? "w" : "a");
>> +      if (!stream)
>> +        error ("could not open dump file %qs: %m", name);
>> +      else
>> +        dfi->state = 1;
>> +      free (name);
>> +    }
>>
>>   if (flag_ptr)
>>     *flag_ptr = dfi->flags;
>> @@ -987,35 +1017,45 @@ dump_flag_name (int phase)
>>    dump_begin.  */
>>
>>  void
>> -dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
>> +dump_end (int phase, FILE *stream)
>>  {
>> -  fclose (stream);
>> +  struct dump_file_info *dfi = get_dump_file_info (phase);
>> +  if (!dump_stream_p (dfi->user_filename))
>> +    fclose (stream);
>>  }
>>
>>  /* Enable all tree dumps.  Return number of enabled tree dumps.  */
>>
>>  static int
>> -dump_enable_all (int flags)
>> +dump_enable_all (int flags, const char *user_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].flags & ir_dump_type))
>> -      {
>> -        dump_files[i].state = -1;
>> -        dump_files[i].flags |= flags;
>> -        n++;
>> -      }
>> +    {
>> +      if ((dump_files[i].flags & ir_dump_type))
>> +        {
>> +          dump_files[i].state = -1;
>> +          dump_files[i].flags |= flags;
>> +          n++;
>> +        }
>> +      if (user_filename)
>> +        dump_files[i].user_filename = user_filename;
>> +    }
>>
>>   for (i = 0; i < extra_dump_files_in_use; i++)
>> -    if ((extra_dump_files[i].flags & ir_dump_type))
>> -      {
>> -        extra_dump_files[i].state = -1;
>> -        extra_dump_files[i].flags |= flags;
>> -       n++;
>> -      }
>> +    {
>> +      if ((extra_dump_files[i].flags & ir_dump_type))
>> +        {
>> +          extra_dump_files[i].state = -1;
>> +          extra_dump_files[i].flags |= flags;
>> +          n++;
>> +        }
>> +      if (user_filename)
>> +        extra_dump_files[i].user_filename = user_filename;
>> +    }
>>
>>   return n;
>>  }
>> @@ -1037,7 +1077,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>>   if (!option_value)
>>     return 0;
>>
>> -  if (*option_value && *option_value != '-')
>> +  if (*option_value && *option_value != '-' && *option_value != '=')
>>     return 0;
>>
>>   ptr = option_value;
>> @@ -1052,17 +1092,30 @@ dump_switch_p_1 (const char *arg, struct dump_file
>>       while (*ptr == '-')
>>        ptr++;
>>       end_ptr = strchr (ptr, '-');
>> +
>>       if (!end_ptr)
>>        end_ptr = ptr + strlen (ptr);
>>       length = end_ptr - ptr;
>>
>> +      if (*ptr == '=')
>> +        {
>> +          /* Interpret rest of the argument as a dump filename.  The
>> +             user provided filename overrides generated dump names as
>> +             well as other command line filenames.  */
>> +          flags |= TDF_USER_FILENAME;
>> +          if (dfi->user_filename)
>> +            free (dfi->user_filename);
>> +          dfi->user_filename = xstrdup (ptr + 1);
>> +          break;
>> +        }
>> +
>>       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;
>> +          {
>> +            flags |= option_ptr->value;
>>            goto found;
>> -         }
>> +          }
>>       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
>>               length, ptr, dfi->swtch);
>>     found:;
>> @@ -1075,7 +1128,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>>   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
>>      known dumps.  */
>>   if (dfi->suffix == NULL)
>> -    dump_enable_all (dfi->flags);
>> +    dump_enable_all (dfi->flags, dfi->user_filename);
>>
>>   return 1;
>>  }
>> @@ -1124,5 +1177,5 @@ dump_function (int phase, tree fn)
>>  bool
>>  enable_rtl_dump_file (void)
>>  {
>> -  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS) > 0;
>> +  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
>>  }
>> Index: tree-pass.h
>> ===================================================================
>> --- tree-pass.h (revision 187265)
>> +++ tree-pass.h (working copy)
>> @@ -84,8 +84,9 @@ enum tree_dump_index
>>  #define TDF_ENUMERATE_LOCALS (1 << 22) /* Enumerate locals by uid.  */
>>  #define TDF_CSELIB     (1 << 23)       /* Dump cselib details.  */
>>  #define TDF_SCEV       (1 << 24)       /* Dump SCEV details.  */
>> +#define TDF_USER_FILENAME    (1 << 25) /* Dump on user provided filename,
>> +                                           instead of constructing one. */
>>
>> -
>>  /* In tree-dump.c */
>>
>>  extern char *get_dump_file_name (int);
>> @@ -222,6 +223,8 @@ struct dump_file_info
>>   const char *suffix;           /* suffix to give output file.  */
>>   const char *swtch;            /* command line switch */
>>   const char *glob;             /* command line glob  */
>> +  const char *user_filename;    /* user provided filename instead of making
>> +                                   up one using dump_base_name + suffix.  */
>>   int flags;                    /* user flags */
>>   int state;                    /* state of play */
>>   int num;                      /* dump file number */
>> Index: testsuite/g++.dg/other/dump-userfile-1.C
>> ===================================================================
>> --- testsuite/g++.dg/other/dump-userfile-1.C    (revision 0)
>> +++ testsuite/g++.dg/other/dump-userfile-1.C    (revision 0)
>> @@ -0,0 +1,11 @@
>> +// Test that the dump to a user-defined file works correctly.
>> +/* { dg-options "-O2 -fdump-tree-original=foobar.dump" } */
>> +
>> +void test (int *b, int *e, int stride)
>> +  {
>> +    for (int *p = b; p != e; p += stride)
>> +      *p = 1;
>> +  }
>> +
>> +/* { dg-final { scan-file foobar.dump ";; Function void test" } } */
>> +/* { dg-final { remove-build-file "foobar.dump" } } */
>>
>> --
>> This patch is available for review at http://codereview.appspot.com/6190057
Gabriel Dos Reis May 9, 2012, 7:22 a.m. UTC | #3
On Wed, May 9, 2012 at 1:46 AM, Sharad Singhai <singhai@google.com> wrote:
[...]

> +@item -fdump-rtl-all=stderr
> +@opindex fdump-rtl-all=stderr

You do not need to have a separate index entry for '=stderr' or '=stdout'.
Rather, expand the description to state this in all the documentation
for -fdump-xxx=yyy.

[...]

> +/* Return non-zero iff the USER_FILENAME corresponds to stdout or
> +   stderr stream.  */
> +
> +static int
> +dump_stream_p (const char *user_filename)
> +{
> +  if (user_filename)
> +    return !strncmp ("stderr", user_filename, 6) ||
> +      !strncmp ("stdout", user_filename, 6);
> +  else
> +    return 0;
> +}

The name is ambiguous.
This function is testing whether its string argument designates one of
the *standard* output streams.  Name it to reflect that..
Have it take the dump state context. Also the coding convention: the binary
operator "||" should be on next line.  In fact the thing could be
simpler.   Instead of
testing over and over again against "stderr" (once in this function, then again
later), just return the corresponding standard FILE* pointer.
Also, this is a case of overuse of strncmp.  If you name the function
dump_get_standard_stream:

    return strcmp("stderr", dfi->user_filename) == 0
       ? stderr
        : stdcmp("stdout", dfi->use_filename)
        ?  stdout
        : NULL;

you can simplify:

> -  name = get_dump_file_name (phase);
>   dfi = get_dump_file_info (phase);
> -  stream = fopen (name, dfi->state < 0 ? "w" : "a");
> -  if (!stream)
> -    error ("could not open dump file %qs: %m", name);
> +  if (dump_stream_p (dfi->user_filename))
> +    {
> +      if (!strncmp ("stderr", dfi->user_filename, 6))
> +        stream = stderr;
> +      else
> +        if (!strncmp ("stdout", dfi->user_filename, 6))
> +          stream = stdout;
> +        else
> +          error ("unknown stream: %qs: %m", dfi->user_filename);
> +      dfi->state = 1;
> +    }
>   else
> -    dfi->state = 1;
> -  free (name);
> +    {
> +      name = get_dump_file_name (phase);
> +      stream = fopen (name, dfi->state < 0 ? "w" : "a");
> +      if (!stream)
> +        error ("could not open dump file %qs: %m", name);
> +      else
> +        dfi->state = 1;
> +      free (name);
> +    }
>
>   if (flag_ptr)
>     *flag_ptr = dfi->flags;
> @@ -987,35 +1017,45 @@ dump_flag_name (int phase)
>    dump_begin.  */
>
>  void
> -dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
> +dump_end (int phase, FILE *stream)
>  {
> -  fclose (stream);
> +  struct dump_file_info *dfi = get_dump_file_info (phase);
> +  if (!dump_stream_p (dfi->user_filename))
> +    fclose (stream);
>  }
>
>  /* Enable all tree dumps.  Return number of enabled tree dumps.  */
>
>  static int
> -dump_enable_all (int flags)
> +dump_enable_all (int flags, const char *user_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].flags & ir_dump_type))
> -      {
> -        dump_files[i].state = -1;
> -        dump_files[i].flags |= flags;
> -        n++;
> -      }
> +    {
> +      if ((dump_files[i].flags & ir_dump_type))
> +        {
> +          dump_files[i].state = -1;
> +          dump_files[i].flags |= flags;
> +          n++;
> +        }
> +      if (user_filename)
> +        dump_files[i].user_filename = user_filename;
> +    }
>
>   for (i = 0; i < extra_dump_files_in_use; i++)
> -    if ((extra_dump_files[i].flags & ir_dump_type))
> -      {
> -        extra_dump_files[i].state = -1;
> -        extra_dump_files[i].flags |= flags;
> -       n++;
> -      }
> +    {
> +      if ((extra_dump_files[i].flags & ir_dump_type))
> +        {
> +          extra_dump_files[i].state = -1;
> +          extra_dump_files[i].flags |= flags;
> +          n++;
> +        }
> +      if (user_filename)
> +        extra_dump_files[i].user_filename = user_filename;
> +    }
>
>   return n;
>  }
> @@ -1037,7 +1077,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>   if (!option_value)
>     return 0;
>
> -  if (*option_value && *option_value != '-')
> +  if (*option_value && *option_value != '-' && *option_value != '=')
>     return 0;
>
>   ptr = option_value;
> @@ -1052,17 +1092,30 @@ dump_switch_p_1 (const char *arg, struct dump_file
>       while (*ptr == '-')
>        ptr++;
>       end_ptr = strchr (ptr, '-');
> +
>       if (!end_ptr)
>        end_ptr = ptr + strlen (ptr);
>       length = end_ptr - ptr;
>
> +      if (*ptr == '=')
> +        {
> +          /* Interpret rest of the argument as a dump filename.  The
> +             user provided filename overrides generated dump names as
> +             well as other command line filenames.  */
> +          flags |= TDF_USER_FILENAME;
> +          if (dfi->user_filename)
> +            free (dfi->user_filename);
> +          dfi->user_filename = xstrdup (ptr + 1);
> +          break;
> +        }
> +
>       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;
> +          {
> +            flags |= option_ptr->value;
>            goto found;
> -         }
> +          }
>       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
>               length, ptr, dfi->swtch);
>     found:;
> @@ -1075,7 +1128,7 @@ dump_switch_p_1 (const char *arg, struct dump_file
>   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
>      known dumps.  */
>   if (dfi->suffix == NULL)
> -    dump_enable_all (dfi->flags);
> +    dump_enable_all (dfi->flags, dfi->user_filename);
>
>   return 1;
>  }
> @@ -1124,5 +1177,5 @@ dump_function (int phase, tree fn)
>  bool
>  enable_rtl_dump_file (void)
>  {
> -  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS) > 0;
> +  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
>  }
> Index: tree-pass.h
> ===================================================================
> --- tree-pass.h (revision 187265)
> +++ tree-pass.h (working copy)
> @@ -84,8 +84,9 @@ enum tree_dump_index
>  #define TDF_ENUMERATE_LOCALS (1 << 22) /* Enumerate locals by uid.  */
>  #define TDF_CSELIB     (1 << 23)       /* Dump cselib details.  */
>  #define TDF_SCEV       (1 << 24)       /* Dump SCEV details.  */
> +#define TDF_USER_FILENAME    (1 << 25) /* Dump on user provided filename,
> +                                           instead of constructing one. */
>
> -
>  /* In tree-dump.c */
>
>  extern char *get_dump_file_name (int);
> @@ -222,6 +223,8 @@ struct dump_file_info
>   const char *suffix;           /* suffix to give output file.  */
>   const char *swtch;            /* command line switch */
>   const char *glob;             /* command line glob  */
> +  const char *user_filename;    /* user provided filename instead of making
> +                                   up one using dump_base_name + suffix.  */

There is "no user" here: we are the users :-)  Just call it "filename".

-- Gaby
diff mbox

Patch

Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 187265)
+++ doc/invoke.texi	(working copy)
@@ -5322,20 +5322,24 @@  Here are some examples showing uses of these optio
 
 @item -d@var{letters}
 @itemx -fdump-rtl-@var{pass}
+@itemx -fdump-rtl-@var{pass}=@var{filename}
 @opindex d
 Says to make debugging dumps during compilation at times specified by
 @var{letters}.  This is used for debugging the RTL-based passes of the
 compiler.  The file names for most of the dumps are made by appending
 a pass number and a word to the @var{dumpname}, and the files are
-created in the directory of the output file.  Note that the pass
-number is computed statically as passes get registered into the pass
-manager.  Thus the numbering is not related to the dynamic order of
-execution of passes.  In particular, a pass installed by a plugin
-could have a number over 200 even if it executed quite early.
-@var{dumpname} is generated from the name of the output file, if
-explicitly specified and it is not an executable, otherwise it is the
-basename of the source file. These switches may have different effects
-when @option{-E} is used for preprocessing.
+created in the directory of the output file. If the
+@option{=@var{filename}} is appended to the longer form of the dump
+option then the dump is done on that file instead of numbered
+files. The filenames stdout and stderr are treated specially. Note
+that the pass number is computed statically as passes get registered
+into the pass manager.  Thus the numbering is not related to the
+dynamic order of execution of passes.  In particular, a pass installed
+by a plugin could have a number over 200 even if it executed quite
+early.  @var{dumpname} is generated from the name of the output file,
+if explicitly specified and it is not an executable, otherwise it is
+the basename of the source file. These switches may have different
+effects when @option{-E} is used for preprocessing.
 
 Debug dumps can be enabled with a @option{-fdump-rtl} switch or some
 @option{-d} option @var{letters}.  Here are the possible
@@ -5599,6 +5603,10 @@  These dumps are defined but always produce empty f
 @opindex fdump-rtl-all
 Produce all the dumps listed above.
 
+@item -fdump-rtl-all=stderr
+@opindex fdump-rtl-all=stderr
+Produce all RTL dumps on stderr.
+
 @item -dA
 @opindex dA
 Annotate the assembler output with miscellaneous debugging information.
@@ -5719,15 +5727,19 @@  counters for each function compiled.
 
 @item -fdump-tree-@var{switch}
 @itemx -fdump-tree-@var{switch}-@var{options}
+@itemx -fdump-tree-@var{switch}-@var{options}=@var{filename}
 @opindex fdump-tree
 Control the dumping at various stages of processing the intermediate
 language tree to a file.  The file name is generated by appending a
 switch specific suffix to the source file name, and the file is
-created in the same directory as the output file.  If the
-@samp{-@var{options}} form is used, @var{options} is a list of
-@samp{-} separated options which control the details of the dump.  Not
-all options are applicable to all dumps; those that are not
-meaningful are ignored.  The following options are available
+created in the same directory as the output file. In case of
+@option{=@var{filename}}, the dump output is on the given file. Note
+that the filenames stdout and stderr are treated specially and dumps
+are done on standard streams. If the @samp{-@var{options}} form is
+used, @var{options} is a list of @samp{-} separated options which
+control the details or location of the dump.  Not all options are
+applicable to all dumps; those that are not meaningful are ignored.
+The following options are available
 
 @table @samp
 @item address
@@ -5765,9 +5777,56 @@  Enable showing the tree dump for each statement.
 Enable showing the EH region number holding each statement.
 @item scev
 Enable showing scalar evolution analysis details.
+@item slim
+Inhibit dumping of members of a scope or body of a function merely
+because that scope has been reached.  Only dump such items when they
+are directly reachable by some other path.  When dumping pretty-printed
+trees, this option inhibits dumping the bodies of control structures.
+@item =@var{filename}
+Instead of using an auto generated name for a dump file, use the
+provided name. For example:
+
+@smallexample
+gcc -O2 -fdump-tree-pre=foobar.dump
+@end smallexample
+
+produces PRE dump in a file named foobar.dump. Similarly
+
+@smallexample
+gcc -O2 -fdump-tree-all=all.dump
+@end smallexample
+
+produces all tree dumps in a file named all.dump.
+
+Note that stdout and stderr are treated specially, and the dumps are
+done on standard streams. In case of any conflicts, the user provided
+filename takes precedence. For example:
+
+@smallexample
+gcc -O2 -fdump-tree-pre=stderr -fdump-tree-pre ...
+gcc -O2 -fdump-tree-pre -fdump-tree-pre=stderr ...
+@end smallexample
+
+Both invocations produce the PRE dump on stderr. Similarly, for the
+following
+
+@smallexample
+gcc -O2 -fdump-tree-all=stderr -fdump-tree-pre ...
+@end smallexample
+
+All the dumps are output on stderr. In the following example,
+
+@smallexample
+gcc -fdump-tree-all -fdump-tree-pre=stderr ...
+@end smallexample
+
+all the dumps are written into named files except the PRE dump, which
+is output on stderr, because @option{-fdump-tree-pre=stderr} takes
+precedence.
+
 @item all
-Turn on all options, except @option{raw}, @option{slim}, @option{verbose}
-and @option{lineno}.
+Turn on all options, except @option{raw}, @option{slim}, @option{verbose},
+@option{lineno}.
 @end table
 
 The following tree dumps are possible:
@@ -5913,6 +5972,10 @@  is made by appending @file{.vrp} to the source fil
 @item all
 @opindex fdump-tree-all
 Enable all the available tree dumps with the flags provided in this option.
+
+@item all=stderr
+@opindex fdump-tree-all=stderr
+Enable all the available tree dumps on the stderr.
 @end table
 
 @item -ftree-vectorizer-verbose=@var{n}
Index: tree-dump.c
===================================================================
--- tree-dump.c	(revision 187265)
+++ tree-dump.c	(working copy)
@@ -773,20 +773,20 @@  dump_node (const_tree t, int flags, FILE *stream)
    tree_dump_index enumeration in tree-pass.h.  */
 static struct dump_file_info dump_files[TDI_end] =
 {
-  {NULL, NULL, NULL, 0, 0, 0},
-  {".cgraph", "ipa-cgraph", NULL, TDF_IPA, 0,  0},
-  {".tu", "translation-unit", NULL, TDF_TREE, 0, 1},
-  {".class", "class-hierarchy", NULL, TDF_TREE, 0, 2},
-  {".original", "tree-original", NULL, TDF_TREE, 0, 3},
-  {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 4},
-  {".nested", "tree-nested", NULL, TDF_TREE, 0, 5},
-  {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6},
-  {".ads", "ada-spec", NULL, 0, 0, 7},
+  {NULL, NULL, NULL, NULL, 0, 0, 0},
+  {".cgraph", "ipa-cgraph", NULL, NULL, TDF_IPA, 0,  0},
+  {".tu", "translation-unit", NULL, NULL, TDF_TREE, 0, 1},
+  {".class", "class-hierarchy", NULL, NULL, TDF_TREE, 0, 2},
+  {".original", "tree-original", NULL, NULL, TDF_TREE, 0, 3},
+  {".gimple", "tree-gimple", NULL, NULL, TDF_TREE, 0, 4},
+  {".nested", "tree-nested", NULL, NULL, TDF_TREE, 0, 5},
+  {".vcg", "tree-vcg", NULL, NULL, TDF_TREE, 0, 6},
+  {".ads", "ada-spec", NULL, NULL, 0, 0, 7},
 #define FIRST_AUTO_NUMBERED_DUMP 8
 
-  {NULL, "tree-all", NULL, TDF_TREE, 0, 0},
-  {NULL, "rtl-all", NULL, TDF_RTL, 0, 0},
-  {NULL, "ipa-all", NULL, TDF_IPA, 0, 0},
+  {NULL, "tree-all", NULL, NULL, TDF_TREE, 0, 0},
+  {NULL, "rtl-all", NULL, NULL, TDF_RTL, 0, 0},
+  {NULL, "ipa-all", NULL, NULL, TDF_IPA, 0, 0},
 };
 
 /* Dynamically registered tree dump files and switches.  */
@@ -802,7 +802,7 @@  struct dump_option_value_info
 };
 
 /* Table of dump options. This must be consistent with the TDF_* flags
-   in tree.h */
+   in tree-pass.h */
 static const struct dump_option_value_info dump_options[] =
 {
   {"address", TDF_ADDRESS},
@@ -892,6 +892,9 @@  get_dump_file_name (int phase)
   if (dfi->state == 0)
     return NULL;
 
+  if (dfi->user_filename)
+    return xstrdup (dfi->user_filename);
+
   if (dfi->num < 0)
     dump_id[0] = '\0';
   else
@@ -911,6 +914,19 @@  get_dump_file_name (int phase)
   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
 }
 
+/* Return non-zero iff the USER_FILENAME corresponds to stdout or
+   stderr stream.  */
+
+static int
+dump_stream_p (const char *user_filename)
+{
+  if (user_filename)
+    return !strncmp ("stderr", user_filename, 6) ||
+      !strncmp ("stdout", user_filename, 6);
+  else
+    return 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.
@@ -926,14 +942,28 @@  dump_begin (int phase, int *flag_ptr)
   if (phase == TDI_none || !dump_enabled_p (phase))
     return NULL;
 
-  name = get_dump_file_name (phase);
   dfi = get_dump_file_info (phase);
-  stream = fopen (name, dfi->state < 0 ? "w" : "a");
-  if (!stream)
-    error ("could not open dump file %qs: %m", name);
+  if (dump_stream_p (dfi->user_filename))
+    {
+      if (!strncmp ("stderr", dfi->user_filename, 6))
+        stream = stderr;
+      else
+        if (!strncmp ("stdout", dfi->user_filename, 6))
+          stream = stdout;
+        else
+          error ("unknown stream: %qs: %m", dfi->user_filename);
+      dfi->state = 1;
+    }
   else
-    dfi->state = 1;
-  free (name);
+    {
+      name = get_dump_file_name (phase);
+      stream = fopen (name, dfi->state < 0 ? "w" : "a");
+      if (!stream)
+        error ("could not open dump file %qs: %m", name);
+      else
+        dfi->state = 1;
+      free (name);
+    }
 
   if (flag_ptr)
     *flag_ptr = dfi->flags;
@@ -987,35 +1017,45 @@  dump_flag_name (int phase)
    dump_begin.  */
 
 void
-dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
+dump_end (int phase, FILE *stream)
 {
-  fclose (stream);
+  struct dump_file_info *dfi = get_dump_file_info (phase);
+  if (!dump_stream_p (dfi->user_filename))
+    fclose (stream);
 }
 
 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
 
 static int
-dump_enable_all (int flags)
+dump_enable_all (int flags, const char *user_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].flags & ir_dump_type))
-      {
-        dump_files[i].state = -1;
-        dump_files[i].flags |= flags;
-        n++;
-      }
+    {
+      if ((dump_files[i].flags & ir_dump_type))
+        {
+          dump_files[i].state = -1;
+          dump_files[i].flags |= flags;
+          n++;
+        }
+      if (user_filename)
+        dump_files[i].user_filename = user_filename;
+    }
 
   for (i = 0; i < extra_dump_files_in_use; i++)
-    if ((extra_dump_files[i].flags & ir_dump_type))
-      {
-        extra_dump_files[i].state = -1;
-        extra_dump_files[i].flags |= flags;
-	n++;
-      }
+    {
+      if ((extra_dump_files[i].flags & ir_dump_type))
+        {
+          extra_dump_files[i].state = -1;
+          extra_dump_files[i].flags |= flags;
+          n++;
+        }
+      if (user_filename)
+        extra_dump_files[i].user_filename = user_filename;
+    }
 
   return n;
 }
@@ -1037,7 +1077,7 @@  dump_switch_p_1 (const char *arg, struct dump_file
   if (!option_value)
     return 0;
 
-  if (*option_value && *option_value != '-')
+  if (*option_value && *option_value != '-' && *option_value != '=')
     return 0;
 
   ptr = option_value;
@@ -1052,17 +1092,30 @@  dump_switch_p_1 (const char *arg, struct dump_file
       while (*ptr == '-')
 	ptr++;
       end_ptr = strchr (ptr, '-');
+
       if (!end_ptr)
 	end_ptr = ptr + strlen (ptr);
       length = end_ptr - ptr;
 
+      if (*ptr == '=')
+        {
+          /* Interpret rest of the argument as a dump filename.  The
+             user provided filename overrides generated dump names as
+             well as other command line filenames.  */
+          flags |= TDF_USER_FILENAME;
+          if (dfi->user_filename)
+            free (dfi->user_filename);
+          dfi->user_filename = xstrdup (ptr + 1);
+          break;
+        }
+
       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;
+          {
+            flags |= option_ptr->value;
 	    goto found;
-	  }
+          }
       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
 	       length, ptr, dfi->swtch);
     found:;
@@ -1075,7 +1128,7 @@  dump_switch_p_1 (const char *arg, struct dump_file
   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
      known dumps.  */
   if (dfi->suffix == NULL)
-    dump_enable_all (dfi->flags);
+    dump_enable_all (dfi->flags, dfi->user_filename);
 
   return 1;
 }
@@ -1124,5 +1177,5 @@  dump_function (int phase, tree fn)
 bool
 enable_rtl_dump_file (void)
 {
-  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS) > 0;
+  return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
 }
Index: tree-pass.h
===================================================================
--- tree-pass.h	(revision 187265)
+++ tree-pass.h	(working copy)
@@ -84,8 +84,9 @@  enum tree_dump_index
 #define TDF_ENUMERATE_LOCALS (1 << 22)	/* Enumerate locals by uid.  */
 #define TDF_CSELIB	(1 << 23)	/* Dump cselib details.  */
 #define TDF_SCEV	(1 << 24)	/* Dump SCEV details.  */
+#define TDF_USER_FILENAME    (1 << 25)	/* Dump on user provided filename,
+                                           instead of constructing one. */
 
-
 /* In tree-dump.c */
 
 extern char *get_dump_file_name (int);
@@ -222,6 +223,8 @@  struct dump_file_info
   const char *suffix;           /* suffix to give output file.  */
   const char *swtch;            /* command line switch */
   const char *glob;             /* command line glob  */
+  const char *user_filename;    /* user provided filename instead of making
+                                   up one using dump_base_name + suffix.  */
   int flags;                    /* user flags */
   int state;                    /* state of play */
   int num;                      /* dump file number */
Index: testsuite/g++.dg/other/dump-userfile-1.C
===================================================================
--- testsuite/g++.dg/other/dump-userfile-1.C	(revision 0)
+++ testsuite/g++.dg/other/dump-userfile-1.C	(revision 0)
@@ -0,0 +1,11 @@ 
+// Test that the dump to a user-defined file works correctly.
+/* { dg-options "-O2 -fdump-tree-original=foobar.dump" } */
+
+void test (int *b, int *e, int stride)
+  {
+    for (int *p = b; p != e; p += stride)
+      *p = 1;
+  }
+
+/* { dg-final { scan-file foobar.dump ";; Function void test" } } */
+/* { dg-final { remove-build-file "foobar.dump" } } */