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