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