Update change log
[platform/upstream/gcc48.git] / gcc / dumpfile.c
1 /* Dump infrastructure for optimizations and intermediate representation.
2    Copyright (C) 2012-2013 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3.  If not see
18 <http://www.gnu.org/licenses/>.  */
19
20 #include "config.h"
21 #include "system.h"
22 #include "coretypes.h"
23 #include "diagnostic-core.h"
24 #include "dumpfile.h"
25 #include "gimple-pretty-print.h"
26 #include "tree.h"
27
28 /* If non-NULL, return one past-the-end of the matching SUBPART of
29    the WHOLE string.  */
30 #define skip_leading_substring(whole,  part) \
31    (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part))
32
33 static int pflags;                   /* current dump_flags */
34 static int alt_flags;                /* current opt_info flags */
35
36 static void dump_loc (int, FILE *, source_location);
37 static int dump_phase_enabled_p (int);
38 static FILE *dump_open_alternate_stream (struct dump_file_info *);
39
40 /* These are currently used for communicating between passes.
41    However, instead of accessing them directly, the passes can use
42    dump_printf () for dumps.  */
43 FILE *dump_file = NULL;
44 FILE *alt_dump_file = NULL;
45 const char *dump_file_name;
46 int dump_flags;
47
48 /* Table of tree dump switches. This must be consistent with the
49    TREE_DUMP_INDEX enumeration in dumpfile.h.  */
50 static struct dump_file_info dump_files[TDI_end] =
51 {
52   {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0},
53   {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
54    0, 0, 0, 0, 0},
55   {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
56    0, 0, 0, 0, 1},
57   {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
58    0, 0, 0, 0, 2},
59   {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
60    0, 0, 0, 0, 3},
61   {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
62    0, 0, 0, 0, 4},
63   {".nested", "tree-nested", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
64    0, 0, 0, 0, 5},
65 #define FIRST_AUTO_NUMBERED_DUMP 6
66
67   {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
68    0, 0, 0, 0, 0},
69   {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL,
70    0, 0, 0, 0, 0},
71   {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
72    0, 0, 0, 0, 0},
73 };
74
75 /* Dynamically registered tree dump files and switches.  */
76 static struct dump_file_info *extra_dump_files;
77 static size_t extra_dump_files_in_use;
78 static size_t extra_dump_files_alloced;
79
80 /* Define a name->number mapping for a dump flag value.  */
81 struct dump_option_value_info
82 {
83   const char *const name;       /* the name of the value */
84   const int value;              /* the value of the name */
85 };
86
87 /* Table of dump options. This must be consistent with the TDF_* flags
88    in dumpfile.h and opt_info_options below. */
89 static const struct dump_option_value_info dump_options[] =
90 {
91   {"address", TDF_ADDRESS},
92   {"asmname", TDF_ASMNAME},
93   {"slim", TDF_SLIM},
94   {"raw", TDF_RAW},
95   {"graph", TDF_GRAPH},
96   {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
97                | MSG_MISSED_OPTIMIZATION
98                | MSG_NOTE)},
99   {"cselib", TDF_CSELIB},
100   {"stats", TDF_STATS},
101   {"blocks", TDF_BLOCKS},
102   {"vops", TDF_VOPS},
103   {"lineno", TDF_LINENO},
104   {"uid", TDF_UID},
105   {"stmtaddr", TDF_STMTADDR},
106   {"memsyms", TDF_MEMSYMS},
107   {"verbose", TDF_VERBOSE},
108   {"eh", TDF_EH},
109   {"alias", TDF_ALIAS},
110   {"nouid", TDF_NOUID},
111   {"enumerate_locals", TDF_ENUMERATE_LOCALS},
112   {"scev", TDF_SCEV},
113   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
114             | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
115             | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)},
116   {NULL, 0}
117 };
118
119 /* A subset of the dump_options table which is used for -fopt-info
120    types. This must be consistent with the MSG_* flags in dumpfile.h.
121  */
122 static const struct dump_option_value_info optinfo_verbosity_options[] =
123 {
124   {"optimized", MSG_OPTIMIZED_LOCATIONS},
125   {"missed", MSG_MISSED_OPTIMIZATION},
126   {"note", MSG_NOTE},
127   {"all", MSG_ALL},
128   {NULL, 0}
129 };
130
131 /* Flags used for -fopt-info groups.  */
132 static const struct dump_option_value_info optgroup_options[] =
133 {
134   {"ipa", OPTGROUP_IPA},
135   {"loop", OPTGROUP_LOOP},
136   {"inline", OPTGROUP_INLINE},
137   {"vec", OPTGROUP_VEC},
138   {"optall", OPTGROUP_ALL},
139   {NULL, 0}
140 };
141
142 unsigned int
143 dump_register (const char *suffix, const char *swtch, const char *glob,
144                int flags, int optgroup_flags)
145 {
146   static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
147   int num = next_dump++;
148
149   size_t count = extra_dump_files_in_use++;
150
151   if (count >= extra_dump_files_alloced)
152     {
153       if (extra_dump_files_alloced == 0)
154         extra_dump_files_alloced = 32;
155       else
156         extra_dump_files_alloced *= 2;
157       extra_dump_files = XRESIZEVEC (struct dump_file_info,
158                                      extra_dump_files,
159                                      extra_dump_files_alloced);
160     }
161
162   memset (&extra_dump_files[count], 0, sizeof (struct dump_file_info));
163   extra_dump_files[count].suffix = suffix;
164   extra_dump_files[count].swtch = swtch;
165   extra_dump_files[count].glob = glob;
166   extra_dump_files[count].pflags = flags;
167   extra_dump_files[count].optgroup_flags = optgroup_flags;
168   extra_dump_files[count].num = num;
169
170   return count + TDI_end;
171 }
172
173
174 /* Return the dump_file_info for the given phase.  */
175
176 struct dump_file_info *
177 get_dump_file_info (int phase)
178 {
179   if (phase < TDI_end)
180     return &dump_files[phase];
181   else if ((size_t) (phase - TDI_end) >= extra_dump_files_in_use)
182     return NULL;
183   else
184     return extra_dump_files + (phase - TDI_end);
185 }
186
187
188 /* Return the name of the dump file for the given phase.
189    If the dump is not enabled, returns NULL.  */
190
191 char *
192 get_dump_file_name (int phase)
193 {
194   char dump_id[10];
195   struct dump_file_info *dfi;
196
197   if (phase == TDI_none)
198     return NULL;
199
200   dfi = get_dump_file_info (phase);
201   if (dfi->pstate == 0)
202     return NULL;
203
204   /* If available, use the command line dump filename. */
205   if (dfi->pfilename)
206     return xstrdup (dfi->pfilename);
207
208   if (dfi->num < 0)
209     dump_id[0] = '\0';
210   else
211     {
212       char suffix;
213       if (dfi->pflags & TDF_TREE)
214         suffix = 't';
215       else if (dfi->pflags & TDF_IPA)
216         suffix = 'i';
217       else
218         suffix = 'r';
219
220       if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
221         dump_id[0] = '\0';
222     }
223
224   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
225 }
226
227 /* For a given DFI, open an alternate dump filename (which could also
228    be a standard stream such as stdout/stderr). If the alternate dump
229    file cannot be opened, return NULL.  */
230
231 static FILE *
232 dump_open_alternate_stream (struct dump_file_info *dfi)
233 {
234   FILE *stream ;
235   if (!dfi->alt_filename)
236     return NULL;
237
238   if (dfi->alt_stream)
239     return dfi->alt_stream;
240
241   stream = strcmp("stderr", dfi->alt_filename) == 0
242     ? stderr
243     : strcmp("stdout", dfi->alt_filename) == 0
244     ?  stdout
245     : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
246
247   if (!stream)
248     error ("could not open dump file %qs: %m", dfi->alt_filename);
249   else
250     dfi->alt_state = 1;
251
252   return stream;
253 }
254
255 /* Print source location on DFILE if enabled.  */
256
257 void
258 dump_loc (int dump_kind, FILE *dfile, source_location loc)
259 {
260   /* Currently vectorization passes print location information.  */
261   if (dump_kind)
262     {
263       if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
264         fprintf (dfile, "\n%s:%d: note: ", LOCATION_FILE (loc),
265                  LOCATION_LINE (loc));
266       else if (current_function_decl)
267         fprintf (dfile, "\n%s:%d: note: ",
268                  DECL_SOURCE_FILE (current_function_decl),
269                  DECL_SOURCE_LINE (current_function_decl));
270     }
271 }
272
273 /* Dump gimple statement GS with SPC indentation spaces and
274    EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled.  */
275
276 void
277 dump_gimple_stmt (int dump_kind, int extra_dump_flags, gimple gs, int spc)
278 {
279   if (dump_file && (dump_kind & pflags))
280     print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
281
282   if (alt_dump_file && (dump_kind & alt_flags))
283     print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
284 }
285
286 /* Similar to dump_gimple_stmt, except additionally print source location.  */
287
288 void
289 dump_gimple_stmt_loc (int dump_kind, source_location loc, int extra_dump_flags,
290                       gimple gs, int spc)
291 {
292   if (dump_file && (dump_kind & pflags))
293     {
294       dump_loc (dump_kind, dump_file, loc);
295       print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
296     }
297
298   if (alt_dump_file && (dump_kind & alt_flags))
299     {
300       dump_loc (dump_kind, alt_dump_file, loc);
301       print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
302     }
303 }
304
305 /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
306    DUMP_KIND is enabled.  */
307
308 void
309 dump_generic_expr (int dump_kind, int extra_dump_flags, tree t)
310 {
311   if (dump_file && (dump_kind & pflags))
312       print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
313
314   if (alt_dump_file && (dump_kind & alt_flags))
315       print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
316 }
317
318
319 /* Similar to dump_generic_expr, except additionally print the source
320    location.  */
321
322 void
323 dump_generic_expr_loc (int dump_kind, source_location loc,
324                        int extra_dump_flags, tree t)
325 {
326   if (dump_file && (dump_kind & pflags))
327     {
328       dump_loc (dump_kind, dump_file, loc);
329       print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
330     }
331
332   if (alt_dump_file && (dump_kind & alt_flags))
333     {
334       dump_loc (dump_kind, alt_dump_file, loc);
335       print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
336     }
337 }
338
339 /* Output a formatted message using FORMAT on appropriate dump streams.  */
340
341 void
342 dump_printf (int dump_kind, const char *format, ...)
343 {
344   if (dump_file && (dump_kind & pflags))
345     {
346       va_list ap;
347       va_start (ap, format);
348       vfprintf (dump_file, format, ap);
349       va_end (ap);
350     }
351
352   if (alt_dump_file && (dump_kind & alt_flags))
353     {
354       va_list ap;
355       va_start (ap, format);
356       vfprintf (alt_dump_file, format, ap);
357       va_end (ap);
358     }
359 }
360
361 /* Similar to dump_printf, except source location is also printed.  */
362
363 void
364 dump_printf_loc (int dump_kind, source_location loc, const char *format, ...)
365 {
366   if (dump_file && (dump_kind & pflags))
367     {
368       va_list ap;
369       dump_loc (dump_kind, dump_file, loc);
370       va_start (ap, format);
371       vfprintf (dump_file, format, ap);
372       va_end (ap);
373     }
374
375   if (alt_dump_file && (dump_kind & alt_flags))
376     {
377       va_list ap;
378       dump_loc (dump_kind, alt_dump_file, loc);
379       va_start (ap, format);
380       vfprintf (alt_dump_file, format, ap);
381       va_end (ap);
382     }
383 }
384
385 /* Start a dump for PHASE. Store user-supplied dump flags in
386    *FLAG_PTR.  Return the number of streams opened.  Set globals
387    DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
388    set dump_flags appropriately for both pass dump stream and
389    -fopt-info stream. */
390
391 int
392 dump_start (int phase, int *flag_ptr)
393 {
394   int count = 0;
395   char *name;
396   struct dump_file_info *dfi;
397   FILE *stream;
398   if (phase == TDI_none || !dump_phase_enabled_p (phase))
399     return 0;
400
401   dfi = get_dump_file_info (phase);
402   name = get_dump_file_name (phase);
403   if (name)
404     {
405       stream = strcmp("stderr", name) == 0
406           ? stderr
407           : strcmp("stdout", name) == 0
408           ?  stdout
409           : fopen (name, dfi->pstate < 0 ? "w" : "a");
410       if (!stream)
411         error ("could not open dump file %qs: %m", name);
412       else
413         {
414           dfi->pstate = 1;
415           count++;
416         }
417       free (name);
418       dfi->pstream = stream;
419       dump_file = dfi->pstream;
420       /* Initialize current dump flags. */
421       pflags = dfi->pflags;
422     }
423
424   stream = dump_open_alternate_stream (dfi);
425   if (stream)
426     {
427       dfi->alt_stream = stream;
428       count++;
429       alt_dump_file = dfi->alt_stream;
430       /* Initialize current -fopt-info flags. */
431       alt_flags = dfi->alt_flags;
432     }
433
434   if (flag_ptr)
435     *flag_ptr = dfi->pflags;
436
437   return count;
438 }
439
440 /* Finish a tree dump for PHASE and close associated dump streams.  Also
441    reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS.  */
442
443 void
444 dump_finish (int phase)
445 {
446   struct dump_file_info *dfi;
447
448   if (phase < 0)
449     return;
450   dfi = get_dump_file_info (phase);
451   if (dfi->pstream)
452     fclose (dfi->pstream);
453
454   if (dfi->alt_stream && strcmp("stderr", dfi->alt_filename) != 0
455       && strcmp("stdout", dfi->alt_filename) != 0)
456     fclose (dfi->alt_stream);
457
458   dfi->alt_stream = NULL;
459   dfi->pstream = NULL;
460   dump_file = NULL;
461   alt_dump_file = NULL;
462   dump_flags = TDI_none;
463   alt_flags = 0;
464   pflags = 0;
465 }
466
467 /* Begin a tree dump for PHASE. Stores any user supplied flag in
468    *FLAG_PTR and returns a stream to write to. If the dump is not
469    enabled, returns NULL.
470    Multiple calls will reopen and append to the dump file.  */
471
472 FILE *
473 dump_begin (int phase, int *flag_ptr)
474 {
475   char *name;
476   struct dump_file_info *dfi;
477   FILE *stream;
478
479   if (phase == TDI_none || !dump_phase_enabled_p (phase))
480     return NULL;
481
482   name = get_dump_file_name (phase);
483   if (!name)
484     return NULL;
485   dfi = get_dump_file_info (phase);
486
487   stream = strcmp("stderr", name) == 0
488     ? stderr
489     : strcmp("stdout", name) == 0
490     ?  stdout
491     : fopen (name, dfi->pstate < 0 ? "w" : "a");
492
493   if (!stream)
494     error ("could not open dump file %qs: %m", name);
495   else
496     dfi->pstate = 1;
497   free (name);
498
499   if (flag_ptr)
500     *flag_ptr = dfi->pflags;
501
502   /* Initialize current flags */
503   pflags = dfi->pflags;
504   return stream;
505 }
506
507 /* Returns nonzero if dump PHASE is enabled for at least one stream.
508    If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
509    any phase.  */
510
511 static int
512 dump_phase_enabled_p (int phase)
513 {
514   if (phase == TDI_tree_all)
515     {
516       size_t i;
517       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
518         if (dump_files[i].pstate || dump_files[i].alt_state)
519           return 1;
520       for (i = 0; i < extra_dump_files_in_use; i++)
521         if (extra_dump_files[i].pstate || extra_dump_files[i].alt_state)
522           return 1;
523       return 0;
524     }
525   else
526     {
527       struct dump_file_info *dfi = get_dump_file_info (phase);
528       return dfi->pstate || dfi->alt_state;
529     }
530 }
531
532 /* Returns nonzero if tree dump PHASE has been initialized.  */
533
534 int
535 dump_initialized_p (int phase)
536 {
537   struct dump_file_info *dfi = get_dump_file_info (phase);
538   return dfi->pstate > 0 || dfi->alt_state > 0;
539 }
540
541 /* Returns the switch name of PHASE.  */
542
543 const char *
544 dump_flag_name (int phase)
545 {
546   struct dump_file_info *dfi = get_dump_file_info (phase);
547   return dfi->swtch;
548 }
549
550 /* Finish a tree dump for PHASE. STREAM is the stream created by
551    dump_begin.  */
552
553 void
554 dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
555 {
556   if (stream != stderr && stream != stdout)
557     fclose (stream);
558 }
559
560 /* Enable all tree dumps with FLAGS on FILENAME.  Return number of
561    enabled tree dumps.  */
562
563 static int
564 dump_enable_all (int flags, const char *filename)
565 {
566   int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
567   int n = 0;
568   size_t i;
569
570   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
571     {
572       if ((dump_files[i].pflags & ir_dump_type))
573         {
574           const char *old_filename = dump_files[i].pfilename;
575           dump_files[i].pstate = -1;
576           dump_files[i].pflags |= flags;
577           n++;
578           /* Override the existing filename.  */
579           if (filename)
580             {
581               dump_files[i].pfilename = xstrdup (filename);
582               /* Since it is a command-line provided file, which is
583                  common to all the phases, use it in append mode.  */
584               dump_files[i].pstate = 1;
585             }
586           if (old_filename && filename != old_filename)
587             free (CONST_CAST (char *, old_filename));
588         }
589     }
590
591   for (i = 0; i < extra_dump_files_in_use; i++)
592     {
593       if ((extra_dump_files[i].pflags & ir_dump_type))
594         {
595           const char *old_filename = extra_dump_files[i].pfilename;
596           extra_dump_files[i].pstate = -1;
597           extra_dump_files[i].pflags |= flags;
598           n++;
599           /* Override the existing filename.  */
600           if (filename)
601             {
602               extra_dump_files[i].pfilename = xstrdup (filename);
603               /* Since it is a command-line provided file, which is
604                  common to all the phases, use it in append mode.  */
605               extra_dump_files[i].pstate = 1;
606             }
607           if (old_filename && filename != old_filename)
608             free (CONST_CAST (char *, old_filename));
609         }
610     }
611
612   return n;
613 }
614
615 /* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
616    Enable dumps with FLAGS on FILENAME.  Return the number of enabled
617    dumps.  */
618
619 static int
620 opt_info_enable_passes (int optgroup_flags, int flags, const char *filename)
621 {
622   int n = 0;
623   size_t i;
624
625   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
626     {
627       if ((dump_files[i].optgroup_flags & optgroup_flags))
628         {
629           const char *old_filename = dump_files[i].alt_filename;
630           /* Since this file is shared among different passes, it
631              should be opened in append mode.  */
632           dump_files[i].alt_state = 1;
633           dump_files[i].alt_flags |= flags;
634           n++;
635           /* Override the existing filename.  */
636           if (filename)
637             dump_files[i].alt_filename = xstrdup (filename);
638           if (old_filename && filename != old_filename)
639             free (CONST_CAST (char *, old_filename));
640         }
641     }
642
643   for (i = 0; i < extra_dump_files_in_use; i++)
644     {
645       if ((extra_dump_files[i].optgroup_flags & optgroup_flags))
646         {
647           const char *old_filename = extra_dump_files[i].alt_filename;
648           /* Since this file is shared among different passes, it
649              should be opened in append mode.  */
650           extra_dump_files[i].alt_state = 1;
651           extra_dump_files[i].alt_flags |= flags;
652           n++;
653           /* Override the existing filename.  */
654           if (filename)
655             extra_dump_files[i].alt_filename = xstrdup (filename);
656           if (old_filename && filename != old_filename)
657             free (CONST_CAST (char *, old_filename));
658         }
659     }
660
661   return n;
662 }
663
664 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
665    relevant details in the dump_files array.  */
666
667 static int
668 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
669 {
670   const char *option_value;
671   const char *ptr;
672   int flags;
673
674   if (doglob && !dfi->glob)
675     return 0;
676
677   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
678   if (!option_value)
679     return 0;
680
681   if (*option_value && *option_value != '-' && *option_value != '=')
682     return 0;
683
684   ptr = option_value;
685   flags = 0;
686
687   while (*ptr)
688     {
689       const struct dump_option_value_info *option_ptr;
690       const char *end_ptr;
691       const char *eq_ptr;
692       unsigned length;
693
694       while (*ptr == '-')
695         ptr++;
696       end_ptr = strchr (ptr, '-');
697       eq_ptr = strchr (ptr, '=');
698
699       if (eq_ptr && !end_ptr)
700         end_ptr = eq_ptr;
701
702       if (!end_ptr)
703         end_ptr = ptr + strlen (ptr);
704       length = end_ptr - ptr;
705
706       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
707         if (strlen (option_ptr->name) == length
708             && !memcmp (option_ptr->name, ptr, length))
709           {
710             flags |= option_ptr->value;
711             goto found;
712           }
713
714       if (*ptr == '=')
715         {
716           /* Interpret rest of the argument as a dump filename.  This
717              filename overrides other command line filenames.  */
718           if (dfi->pfilename)
719             free (CONST_CAST (char *, dfi->pfilename));
720           dfi->pfilename = xstrdup (ptr + 1);
721           break;
722         }
723       else
724         warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
725                  length, ptr, dfi->swtch);
726     found:;
727       ptr = end_ptr;
728     }
729
730   dfi->pstate = -1;
731   dfi->pflags |= flags;
732
733   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
734      known dumps.  */
735   if (dfi->suffix == NULL)
736     dump_enable_all (dfi->pflags, dfi->pfilename);
737
738   return 1;
739 }
740
741 int
742 dump_switch_p (const char *arg)
743 {
744   size_t i;
745   int any = 0;
746
747   for (i = TDI_none + 1; i != TDI_end; i++)
748     any |= dump_switch_p_1 (arg, &dump_files[i], false);
749
750   /* Don't glob if we got a hit already */
751   if (!any)
752     for (i = TDI_none + 1; i != TDI_end; i++)
753       any |= dump_switch_p_1 (arg, &dump_files[i], true);
754
755   for (i = 0; i < extra_dump_files_in_use; i++)
756     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
757
758   if (!any)
759     for (i = 0; i < extra_dump_files_in_use; i++)
760       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
761
762
763   return any;
764 }
765
766 /* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
767    and filename.  Return non-zero if it is a recognized switch.  */
768
769 static int
770 opt_info_switch_p_1 (const char *arg, int *flags, int *optgroup_flags,
771                      char **filename)
772 {
773   const char *option_value;
774   const char *ptr;
775
776   option_value = arg;
777   ptr = option_value;
778
779   *filename = NULL;
780   *flags = 0;
781   *optgroup_flags = 0;
782
783   if (!ptr)
784     return 1;       /* Handle '-fopt-info' without any additional options.  */
785
786   while (*ptr)
787     {
788       const struct dump_option_value_info *option_ptr;
789       const char *end_ptr;
790       const char *eq_ptr;
791       unsigned length;
792
793       while (*ptr == '-')
794         ptr++;
795       end_ptr = strchr (ptr, '-');
796       eq_ptr = strchr (ptr, '=');
797
798       if (eq_ptr && !end_ptr)
799         end_ptr = eq_ptr;
800
801       if (!end_ptr)
802         end_ptr = ptr + strlen (ptr);
803       length = end_ptr - ptr;
804
805       for (option_ptr = optinfo_verbosity_options; option_ptr->name;
806            option_ptr++)
807         if (strlen (option_ptr->name) == length
808             && !memcmp (option_ptr->name, ptr, length))
809           {
810             *flags |= option_ptr->value;
811             goto found;
812           }
813
814       for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
815         if (strlen (option_ptr->name) == length
816             && !memcmp (option_ptr->name, ptr, length))
817           {
818             *optgroup_flags |= option_ptr->value;
819             goto found;
820           }
821
822       if (*ptr == '=')
823         {
824           /* Interpret rest of the argument as a dump filename.  This
825              filename overrides other command line filenames.  */
826           *filename = xstrdup (ptr + 1);
827           break;
828         }
829       else
830         {
831           warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
832                    length, ptr, arg);
833           return 0;
834         }
835     found:;
836       ptr = end_ptr;
837     }
838
839   return 1;
840 }
841
842 /* Return non-zero if ARG is a recognized switch for
843    -fopt-info. Return zero otherwise.  */
844
845 int
846 opt_info_switch_p (const char *arg)
847 {
848   int flags;
849   int optgroup_flags;
850   char *filename;
851   static char *file_seen = NULL;
852
853   if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
854     return 0;
855
856   if (!filename)
857     filename = xstrdup ("stderr");
858
859   /* Bail out if a different filename has been specified.  */
860   if (file_seen && strcmp (file_seen, filename))
861     {
862       warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
863                arg);
864       return 1;
865     }
866
867   file_seen = xstrdup (filename);
868   if (!flags)
869     flags = MSG_ALL;
870   if (!optgroup_flags)
871     optgroup_flags = OPTGROUP_ALL;
872
873   return opt_info_enable_passes (optgroup_flags, flags, filename);
874 }
875
876 /* Print basic block on the dump streams.  */
877
878 void
879 dump_basic_block (int dump_kind, basic_block bb, int indent)
880 {
881   if (dump_file && (dump_kind & pflags))
882     dump_bb (dump_file, bb, indent, TDF_DETAILS);
883   if (alt_dump_file && (dump_kind & alt_flags))
884     dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
885 }
886
887 /* Print information from the combine pass on dump_file.  */
888
889 void
890 print_combine_total_stats (void)
891 {
892   if (dump_file)
893     dump_combine_total_stats (dump_file);
894 }
895
896 /* Enable RTL dump for all the RTL passes.  */
897
898 bool
899 enable_rtl_dump_file (void)
900 {
901   return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;
902 }