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