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