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 
dump_manager()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 
~dump_manager()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::
dump_register(const char * suffix,const char * swtch,const char * glob,int flags,int optgroup_flags,bool take_ownership)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::
get_dump_file_info(int phase)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::
get_dump_file_info_by_switch(const char * swtch)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::
get_dump_file_name(int phase)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::
get_dump_file_name(struct dump_file_info * dfi)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 *
dump_open_alternate_stream(struct dump_file_info * dfi)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
dump_loc(int dump_kind,FILE * dfile,source_location loc)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
dump_gimple_stmt(int dump_kind,int extra_dump_flags,gimple * gs,int spc)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
dump_gimple_stmt_loc(int dump_kind,source_location loc,int extra_dump_flags,gimple * gs,int spc)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
dump_generic_expr(int dump_kind,int extra_dump_flags,tree t)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
dump_generic_expr_loc(int dump_kind,source_location loc,int extra_dump_flags,tree t)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
dump_printf(int dump_kind,const char * format,...)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
dump_printf_loc(int dump_kind,source_location loc,const char * format,...)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::
dump_start(int phase,int * flag_ptr)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::
dump_finish(int phase)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 *
dump_begin(int phase,int * flag_ptr)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::
dump_begin(int phase,int * flag_ptr)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::
dump_phase_enabled_p(int phase)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::
dump_initialized_p(int phase)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 *
dump_flag_name(int phase)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::
dump_flag_name(int phase)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
dump_end(int phase ATTRIBUTE_UNUSED,FILE * stream)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::
dump_enable_all(int flags,const char * filename)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::
opt_info_enable_passes(int optgroup_flags,int flags,const char * filename)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::
dump_switch_p_1(const char * arg,struct dump_file_info * dfi,bool doglob)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::
dump_switch_p(const char * arg)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
opt_info_switch_p_1(const char * arg,int * flags,int * optgroup_flags,char ** filename)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
opt_info_switch_p(const char * arg)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
dump_basic_block(int dump_kind,basic_block bb,int indent)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
print_combine_total_stats(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
enable_rtl_dump_file(void)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 }
999