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