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