[ARM/AArch64][testsuite] Add vmull tests.
[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 "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
45 static int pflags; /* current dump_flags */
46 static int alt_flags; /* current opt_info flags */
47
48 static void dump_loc (int, FILE *, source_location);
49 static 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. */
54 FILE *dump_file = NULL;
55 FILE *alt_dump_file = NULL;
56 const char *dump_file_name;
57 int dump_flags;
58
59 /* Table of tree dump switches. This must be consistent with the
60 TREE_DUMP_INDEX enumeration in dumpfile.h. */
61 static 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. */
89 struct 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. */
97 static 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 */
134 static 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. */
144 static 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
154 gcc::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
162 gcc::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
183 unsigned int
184 gcc::dump_manager::
185 dump_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
219 struct dump_file_info *
220 gcc::dump_manager::
221 get_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
234 struct dump_file_info *
235 gcc::dump_manager::
236 get_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
252 char *
253 gcc::dump_manager::
254 get_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
271 char *
272 gcc::dump_manager::
273 get_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
309 static FILE *
310 dump_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
335 void
336 dump_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
354 void
355 dump_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
366 void
367 dump_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
386 void
387 dump_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
400 void
401 dump_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
419 void
420 dump_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
441 void
442 dump_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
469 int
470 gcc::dump_manager::
471 dump_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
522 void
523 gcc::dump_manager::
524 dump_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
554 FILE *
555 dump_begin (int phase, int *flag_ptr)
556 {
557 return g->get_dumps ()->dump_begin (phase, flag_ptr);
558 }
559
560 FILE *
561 gcc::dump_manager::
562 dump_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
600 int
601 gcc::dump_manager::
602 dump_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
624 int
625 gcc::dump_manager::
626 dump_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
634 const char *
635 dump_flag_name (int phase)
636 {
637 return g->get_dumps ()->dump_flag_name (phase);
638 }
639
640 const char *
641 gcc::dump_manager::
642 dump_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
651 void
652 dump_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
661 int
662 gcc::dump_manager::
663 dump_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
718 int
719 gcc::dump_manager::
720 opt_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
767 int
768 gcc::dump_manager::
769 dump_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
842 int
843 gcc::dump_manager::
844 dump_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
871 static int
872 opt_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
947 int
948 opt_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
981 void
982 dump_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
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 (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL);
1007 return num_enabled > 0;
1008 }