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