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