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