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