OSDN Git Service

* c-common.h (enum rid): Remove RID_BOUNDED, RID_UNBOUNDED.
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
3    Written by Mark Mitchell <mark@codesourcery.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING.  If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
20 02111-1307, USA.  */
21
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "tree.h"
27 #include "splay-tree.h"
28 #include "diagnostic.h"
29 #include "toplev.h"
30 #include "tree-dump.h"
31 #include "langhooks.h"
32
33 static unsigned int queue PARAMS ((dump_info_p, tree, int));
34 static void dump_index PARAMS ((dump_info_p, unsigned int));
35 static void dequeue_and_dump PARAMS ((dump_info_p));
36 static void dump_new_line PARAMS ((dump_info_p));
37 static void dump_maybe_newline PARAMS ((dump_info_p));
38 static void dump_string_field PARAMS ((dump_info_p, const char *, const char *));
39
40 /* Add T to the end of the queue of nodes to dump.  Returns the index
41    assigned to T.  */
42
43 static unsigned int
44 queue (di, t, flags)
45      dump_info_p di;
46      tree t;
47      int flags;
48 {
49   dump_queue_p dq;
50   dump_node_info_p dni;
51   unsigned int index;
52
53   /* Assign the next available index to T.  */
54   index = ++di->index;
55
56   /* Obtain a new queue node.  */
57   if (di->free_list)
58     {
59       dq = di->free_list;
60       di->free_list = dq->next;
61     }
62   else
63     dq = (dump_queue_p) xmalloc (sizeof (struct dump_queue));
64
65   /* Create a new entry in the splay-tree.  */
66   dni = (dump_node_info_p) xmalloc (sizeof (struct dump_node_info));
67   dni->index = index;
68   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
69   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
70                                 (splay_tree_value) dni);
71
72   /* Add it to the end of the queue.  */
73   dq->next = 0;
74   if (!di->queue_end)
75     di->queue = dq;
76   else
77     di->queue_end->next = dq;
78   di->queue_end = dq;
79
80   /* Return the index.  */
81   return index;
82 }
83
84 static void
85 dump_index (di, index)
86      dump_info_p di;
87      unsigned int index;
88 {
89   fprintf (di->stream, "@%-6u ", index);
90   di->column += 8;
91 }
92
93 /* If T has not already been output, queue it for subsequent output.
94    FIELD is a string to print before printing the index.  Then, the
95    index of T is printed.  */
96
97 void
98 queue_and_dump_index (di, field, t, flags)
99      dump_info_p di;
100      const char *field;
101      tree t;
102      int flags;
103 {
104   unsigned int index;
105   splay_tree_node n;
106
107   /* If there's no node, just return.  This makes for fewer checks in
108      our callers.  */
109   if (!t)
110     return;
111
112   /* See if we've already queued or dumped this node.  */
113   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
114   if (n)
115     index = ((dump_node_info_p) n->value)->index;
116   else
117     /* If we haven't, add it to the queue.  */
118     index = queue (di, t, flags);
119
120   /* Print the index of the node.  */
121   dump_maybe_newline (di);
122   fprintf (di->stream, "%-4s: ", field);
123   di->column += 6;
124   dump_index (di, index);
125 }
126
127 /* Dump the type of T.  */
128
129 void
130 queue_and_dump_type (di, t)
131      dump_info_p di;
132      tree t;
133 {
134   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
135 }
136
137 /* Dump column control */
138 #define SOL_COLUMN 25           /* Start of line column.  */
139 #define EOL_COLUMN 55           /* End of line column.  */
140 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
141
142 /* Insert a new line in the dump output, and indent to an appropriate
143    place to start printing more fields.  */
144
145 static void
146 dump_new_line (di)
147      dump_info_p di;
148 {
149   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
150   di->column = SOL_COLUMN;
151 }
152
153 /* If necessary, insert a new line.  */
154
155 static void
156 dump_maybe_newline (di)
157      dump_info_p di;
158 {
159   int extra;
160
161   /* See if we need a new line.  */
162   if (di->column > EOL_COLUMN)
163     dump_new_line (di);
164   /* See if we need any padding.  */
165   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
166     {
167       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
168       di->column += COLUMN_ALIGNMENT - extra;
169     }
170 }
171
172 /* Dump pointer PTR using FIELD to identify it.  */
173
174 void
175 dump_pointer (di, field, ptr)
176      dump_info_p di;
177      const char *field;
178      void *ptr;
179 {
180   dump_maybe_newline (di);
181   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
182   di->column += 15;
183 }
184
185 /* Dump integer I using FIELD to identify it.  */
186
187 void
188 dump_int (di, field, i)
189      dump_info_p di;
190      const char *field;
191      int i;
192 {
193   dump_maybe_newline (di);
194   fprintf (di->stream, "%-4s: %-7d ", field, i);
195   di->column += 14;
196 }
197
198 /* Dump the string S.  */
199
200 void
201 dump_string (di, string)
202      dump_info_p di;
203      const char *string;
204 {
205   dump_maybe_newline (di);
206   fprintf (di->stream, "%-13s ", string);
207   if (strlen (string) > 13)
208     di->column += strlen (string) + 1;
209   else
210     di->column += 14;
211 }
212
213 /* Dump the string field S.  */
214
215 static void
216 dump_string_field (di, field, string)
217      dump_info_p di;
218      const char *field;
219      const char *string;
220 {
221   dump_maybe_newline (di);
222   fprintf (di->stream, "%-4s: %-7s ", field, string);
223   if (strlen (string) > 7)
224     di->column += 6 + strlen (string) + 1;
225   else
226     di->column += 14;
227 }
228
229 /* Dump the next node in the queue.  */
230
231 static void
232 dequeue_and_dump (di)
233      dump_info_p di;
234 {
235   dump_queue_p dq;
236   splay_tree_node stn;
237   dump_node_info_p dni;
238   tree t;
239   unsigned int index;
240   enum tree_code code;
241   char code_class;
242   const char* code_name;
243
244   /* Get the next node from the queue.  */
245   dq = di->queue;
246   stn = dq->node;
247   t = (tree) stn->key;
248   dni = (dump_node_info_p) stn->value;
249   index = dni->index;
250
251   /* Remove the node from the queue, and put it on the free list.  */
252   di->queue = dq->next;
253   if (!di->queue)
254     di->queue_end = 0;
255   dq->next = di->free_list;
256   di->free_list = dq;
257
258   /* Print the node index.  */
259   dump_index (di, index);
260   /* And the type of node this is.  */
261   if (dni->binfo_p)
262     code_name = "binfo";
263   else
264     code_name = tree_code_name[(int) TREE_CODE (t)];
265   fprintf (di->stream, "%-16s ", code_name);
266   di->column = 25;
267
268   /* Figure out what kind of node this is.  */
269   code = TREE_CODE (t);
270   code_class = TREE_CODE_CLASS (code);
271
272   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
273      more informative.  */
274   if (dni->binfo_p)
275     {
276       unsigned ix;
277       tree bases = BINFO_BASETYPES (t);
278       unsigned n_bases = bases ? TREE_VEC_LENGTH (bases): 0;
279       tree accesses = BINFO_BASEACCESSES (t);
280       
281       dump_child ("type", BINFO_TYPE (t));
282
283       if (TREE_VIA_VIRTUAL (t))
284         dump_string (di, "virt");
285
286       dump_int (di, "bases", n_bases);
287       for (ix = 0; ix != n_bases; ix++)
288         {
289           tree base = TREE_VEC_ELT (bases, ix);
290           tree access = (accesses ? TREE_VEC_ELT (accesses, ix)
291                          : access_public_node);
292           const char *string = NULL;
293
294           if (access == access_public_node)
295             string = "pub";
296           else if (access == access_protected_node)
297             string = "prot";
298           else if (access == access_private_node)
299             string = "priv";
300           else
301             abort ();
302           
303           dump_string (di, string);
304           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
305         }
306       
307       goto done;
308     }
309
310   /* We can knock off a bunch of expression nodes in exactly the same
311      way.  */
312   if (IS_EXPR_CODE_CLASS (code_class))
313     {
314       /* If we're dumping children, dump them now.  */
315       queue_and_dump_type (di, t);
316
317       switch (code_class)
318         {
319         case '1':
320           dump_child ("op 0", TREE_OPERAND (t, 0));
321           break;
322
323         case '2':
324         case '<':
325           dump_child ("op 0", TREE_OPERAND (t, 0));
326           dump_child ("op 1", TREE_OPERAND (t, 1));
327           break;
328
329         case 'e':
330           /* These nodes are handled explicitly below.  */
331           break;
332
333         default:
334           abort ();
335         }
336     }
337   else if (DECL_P (t))
338     {
339       /* All declarations have names.  */
340       if (DECL_NAME (t))
341         dump_child ("name", DECL_NAME (t));
342       if (DECL_ASSEMBLER_NAME_SET_P (t)
343           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
344         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
345       /* And types.  */
346       queue_and_dump_type (di, t);
347       dump_child ("scpe", DECL_CONTEXT (t));
348       /* And a source position.  */
349       if (DECL_SOURCE_FILE (t))
350         {
351           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
352           if (!filename)
353             filename = DECL_SOURCE_FILE (t);
354           else
355             /* Skip the slash.  */
356             ++filename;
357
358           dump_maybe_newline (di);
359           fprintf (di->stream, "srcp: %s:%-6d ", filename,
360                    DECL_SOURCE_LINE (t));
361           di->column += 6 + strlen (filename) + 8;
362         }
363       /* And any declaration can be compiler-generated.  */
364       if (DECL_ARTIFICIAL (t))
365         dump_string (di, "artificial");
366       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
367         dump_child ("chan", TREE_CHAIN (t));
368     }
369   else if (code_class == 't')
370     {
371       /* All types have qualifiers.  */
372       int quals = (*lang_hooks.tree_dump.type_quals) (t);
373
374       if (quals != TYPE_UNQUALIFIED)
375         {
376           fprintf (di->stream, "qual: %c%c%c     ",
377                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
378                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
379                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
380           di->column += 14;
381         }
382
383       /* All types have associated declarations.  */
384       dump_child ("name", TYPE_NAME (t));
385
386       /* All types have a main variant.  */
387       if (TYPE_MAIN_VARIANT (t) != t)
388         dump_child ("unql", TYPE_MAIN_VARIANT (t));
389
390       /* And sizes.  */
391       dump_child ("size", TYPE_SIZE (t));
392
393       /* All types have alignments.  */
394       dump_int (di, "algn", TYPE_ALIGN (t));
395     }
396   else if (code_class == 'c')
397     /* All constants can have types.  */
398     queue_and_dump_type (di, t);
399
400   /* Give the language-specific code a chance to print something.  If
401      it's completely taken care of things, don't bother printing
402      anything more ourselves.  */
403   if ((*lang_hooks.tree_dump.dump_tree) (di, t))
404     goto done;
405
406   /* Now handle the various kinds of nodes.  */
407   switch (code)
408     {
409       int i;
410
411     case IDENTIFIER_NODE:
412       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
413       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
414       break;
415
416     case TREE_LIST:
417       dump_child ("purp", TREE_PURPOSE (t));
418       dump_child ("valu", TREE_VALUE (t));
419       dump_child ("chan", TREE_CHAIN (t));
420       break;
421
422     case TREE_VEC:
423       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
424       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
425         {
426           char buffer[32];
427           sprintf (buffer, "%u", i);
428           dump_child (buffer, TREE_VEC_ELT (t, i));
429         }
430       break;
431
432     case INTEGER_TYPE:
433     case ENUMERAL_TYPE:
434       dump_int (di, "prec", TYPE_PRECISION (t));
435       if (TREE_UNSIGNED (t))
436         dump_string (di, "unsigned");
437       dump_child ("min", TYPE_MIN_VALUE (t));
438       dump_child ("max", TYPE_MAX_VALUE (t));
439
440       if (code == ENUMERAL_TYPE)
441         dump_child ("csts", TYPE_VALUES (t));
442       break;
443
444     case REAL_TYPE:
445       dump_int (di, "prec", TYPE_PRECISION (t));
446       break;
447
448     case POINTER_TYPE:
449       dump_child ("ptd", TREE_TYPE (t));
450       break;
451
452     case REFERENCE_TYPE:
453       dump_child ("refd", TREE_TYPE (t));
454       break;
455
456     case METHOD_TYPE:
457       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
458       /* Fall through.  */
459
460     case FUNCTION_TYPE:
461       dump_child ("retn", TREE_TYPE (t));
462       dump_child ("prms", TYPE_ARG_TYPES (t));
463       break;
464
465     case ARRAY_TYPE:
466       dump_child ("elts", TREE_TYPE (t));
467       dump_child ("domn", TYPE_DOMAIN (t));
468       break;
469
470     case RECORD_TYPE:
471     case UNION_TYPE:
472       if (TREE_CODE (t) == RECORD_TYPE)
473         dump_string (di, "struct");
474       else
475         dump_string (di, "union");
476
477       dump_child ("flds", TYPE_FIELDS (t));
478       dump_child ("fncs", TYPE_METHODS (t));
479       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
480                             DUMP_BINFO);
481       break;
482
483     case CONST_DECL:
484       dump_child ("cnst", DECL_INITIAL (t));
485       break;
486
487     case VAR_DECL:
488     case PARM_DECL:
489     case FIELD_DECL:
490     case RESULT_DECL:
491       if (TREE_CODE (t) == PARM_DECL)
492         dump_child ("argt", DECL_ARG_TYPE (t));
493       else
494         dump_child ("init", DECL_INITIAL (t));
495       dump_child ("size", DECL_SIZE (t));
496       dump_int (di, "algn", DECL_ALIGN (t));
497
498       if (TREE_CODE (t) == FIELD_DECL)
499         {
500           if (DECL_FIELD_OFFSET (t))
501             dump_child ("bpos", bit_position (t));
502         }
503       else if (TREE_CODE (t) == VAR_DECL
504                || TREE_CODE (t) == PARM_DECL)
505         {
506           dump_int (di, "used", TREE_USED (t));
507           if (DECL_REGISTER (t))
508             dump_string (di, "register");
509         }
510       break;
511
512     case FUNCTION_DECL:
513       dump_child ("args", DECL_ARGUMENTS (t));
514       if (DECL_EXTERNAL (t))
515         dump_string (di, "undefined");
516       if (TREE_PUBLIC (t))
517         dump_string (di, "extern");
518       else
519         dump_string (di, "static");
520       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
521         dump_child ("body", DECL_SAVED_TREE (t));
522       break;
523
524     case INTEGER_CST:
525       if (TREE_INT_CST_HIGH (t))
526         dump_int (di, "high", TREE_INT_CST_HIGH (t));
527       dump_int (di, "low", TREE_INT_CST_LOW (t));
528       break;
529
530     case STRING_CST:
531       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
532       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
533       break;
534
535     case TRUTH_NOT_EXPR:
536     case ADDR_EXPR:
537     case INDIRECT_REF:
538     case CLEANUP_POINT_EXPR:
539     case SAVE_EXPR:
540       /* These nodes are unary, but do not have code class `1'.  */
541       dump_child ("op 0", TREE_OPERAND (t, 0));
542       break;
543
544     case TRUTH_ANDIF_EXPR:
545     case TRUTH_ORIF_EXPR:
546     case INIT_EXPR:
547     case MODIFY_EXPR:
548     case COMPONENT_REF:
549     case COMPOUND_EXPR:
550     case ARRAY_REF:
551     case PREDECREMENT_EXPR:
552     case PREINCREMENT_EXPR:
553     case POSTDECREMENT_EXPR:
554     case POSTINCREMENT_EXPR:
555       /* These nodes are binary, but do not have code class `2'.  */
556       dump_child ("op 0", TREE_OPERAND (t, 0));
557       dump_child ("op 1", TREE_OPERAND (t, 1));
558       break;
559
560     case COND_EXPR:
561       dump_child ("op 0", TREE_OPERAND (t, 0));
562       dump_child ("op 1", TREE_OPERAND (t, 1));
563       dump_child ("op 2", TREE_OPERAND (t, 2));
564       break;
565
566     case CALL_EXPR:
567       dump_child ("fn", TREE_OPERAND (t, 0));
568       dump_child ("args", TREE_OPERAND (t, 1));
569       break;
570
571     case CONSTRUCTOR:
572       dump_child ("elts", CONSTRUCTOR_ELTS (t));
573       break;
574
575     case BIND_EXPR:
576       dump_child ("vars", TREE_OPERAND (t, 0));
577       dump_child ("body", TREE_OPERAND (t, 1));
578       break;
579
580     case LOOP_EXPR:
581       dump_child ("body", TREE_OPERAND (t, 0));
582       break;
583
584     case EXIT_EXPR:
585       dump_child ("cond", TREE_OPERAND (t, 0));
586       break;
587
588     case TARGET_EXPR:
589       dump_child ("decl", TREE_OPERAND (t, 0));
590       dump_child ("init", TREE_OPERAND (t, 1));
591       dump_child ("clnp", TREE_OPERAND (t, 2));
592       /* There really are two possible places the initializer can be.
593          After RTL expansion, the second operand is moved to the
594          position of the fourth operand, and the second operand
595          becomes NULL.  */
596       dump_child ("init", TREE_OPERAND (t, 3));
597       break;
598
599     case EXPR_WITH_FILE_LOCATION:
600       dump_child ("expr", EXPR_WFL_NODE (t));
601       break;
602
603     default:
604       /* There are no additional fields to print.  */
605       break;
606     }
607
608  done:
609   if (dump_flag (di, TDF_ADDRESS, NULL))
610     dump_pointer (di, "addr", (void *)t);
611
612   /* Terminate the line.  */
613   fprintf (di->stream, "\n");
614 }
615
616 /* Return nonzero if FLAG has been specified for the dump, and NODE
617    is not the root node of the dump.  */
618
619 int dump_flag (di, flag, node)
620      dump_info_p di;
621      int flag;
622      tree node;
623 {
624   return (di->flags & flag) && (node != di->node);
625 }
626
627 /* Dump T, and all its children, on STREAM.  */
628
629 void
630 dump_node (t, flags, stream)
631      tree t;
632      int flags;
633      FILE *stream;
634 {
635   struct dump_info di;
636   dump_queue_p dq;
637   dump_queue_p next_dq;
638
639   /* Initialize the dump-information structure.  */
640   di.stream = stream;
641   di.index = 0;
642   di.column = 0;
643   di.queue = 0;
644   di.queue_end = 0;
645   di.free_list = 0;
646   di.flags = flags;
647   di.node = t;
648   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
649                              (splay_tree_delete_value_fn) &free);
650
651   /* Queue up the first node.  */
652   queue (&di, t, DUMP_NONE);
653
654   /* Until the queue is empty, keep dumping nodes.  */
655   while (di.queue)
656     dequeue_and_dump (&di);
657
658   /* Now, clean up.  */
659   for (dq = di.free_list; dq; dq = next_dq)
660     {
661       next_dq = dq->next;
662       free (dq);
663     }
664   splay_tree_delete (di.nodes);
665 }
666
667 /* Define a tree dump switch.  */
668 struct dump_file_info
669 {
670   const char *const suffix;     /* suffix to give output file.  */
671   const char *const swtch;      /* command line switch */
672   int flags;                    /* user flags */
673   int state;                    /* state of play */
674 };
675
676 /* Table of tree dump switches. This must be consistent with the
677    TREE_DUMP_INDEX enumeration in tree.h */
678 static struct dump_file_info dump_files[TDI_end] =
679 {
680   {".tu", "dump-translation-unit", 0, 0},
681   {".class", "dump-class-hierarchy", 0, 0},
682   {".original", "dump-tree-original", 0, 0},
683   {".optimized", "dump-tree-optimized", 0, 0},
684   {".inlined", "dump-tree-inlined", 0, 0},
685 };
686
687 /* Define a name->number mapping for a dump flag value.  */
688 struct dump_option_value_info
689 {
690   const char *const name;       /* the name of the value */
691   const int value;              /* the value of the name */
692 };
693
694 /* Table of dump options. This must be consistent with the TDF_* flags
695    in tree.h */
696 static const struct dump_option_value_info dump_options[] =
697 {
698   {"address", TDF_ADDRESS},
699   {"slim", TDF_SLIM},
700   {"all", ~0},
701   {NULL, 0}
702 };
703
704 /* Begin a tree dump for PHASE. Stores any user supplied flag in
705    *FLAG_PTR and returns a stream to write to. If the dump is not
706    enabled, returns NULL.
707    Multiple calls will reopen and append to the dump file.  */
708
709 FILE *
710 dump_begin (phase, flag_ptr)
711      enum tree_dump_index phase;
712      int *flag_ptr;
713 {
714   FILE *stream;
715   char *name;
716
717   if (!dump_files[phase].state)
718     return NULL;
719
720   name = concat (dump_base_name, dump_files[phase].suffix, NULL);
721   stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
722   if (!stream)
723     error ("could not open dump file `%s'", name);
724   else
725     dump_files[phase].state = 1;
726   free (name);
727   if (flag_ptr)
728     *flag_ptr = dump_files[phase].flags;
729
730   return stream;
731 }
732
733 /* Returns nonzero if tree dump PHASE is enabled.  */
734
735 int
736 dump_enabled_p (phase)
737      enum tree_dump_index phase;
738 {
739   return dump_files[phase].state;
740 }
741
742 /* Returns the switch name of PHASE.  */
743
744 const char *
745 dump_flag_name (phase)
746      enum tree_dump_index phase;
747 {
748   return dump_files[phase].swtch;
749 }
750
751 /* Finish a tree dump for PHASE. STREAM is the stream created by
752    dump_begin.  */
753
754 void
755 dump_end (phase, stream)
756      enum tree_dump_index phase ATTRIBUTE_UNUSED;
757      FILE *stream;
758 {
759   fclose (stream);
760 }
761
762 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
763    relevant details in the dump_files array.  */
764
765 int
766 dump_switch_p (arg)
767      const char *arg;
768 {
769   unsigned ix;
770   const char *option_value;
771
772   for (ix = 0; ix != TDI_end; ix++)
773     if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
774       {
775         const char *ptr = option_value;
776         int flags = 0;
777
778         while (*ptr)
779           {
780             const struct dump_option_value_info *option_ptr;
781             const char *end_ptr;
782             unsigned length;
783
784             while (*ptr == '-')
785               ptr++;
786             end_ptr = strchr (ptr, '-');
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;
792                  option_ptr++)
793               if (strlen (option_ptr->name) == length
794                   && !memcmp (option_ptr->name, ptr, length))
795                 {
796                   flags |= option_ptr->value;
797                   goto found;
798                 }
799             warning ("ignoring unknown option `%.*s' in `-f%s'",
800                      length, ptr, dump_files[ix].swtch);
801           found:;
802             ptr = end_ptr;
803           }
804
805         dump_files[ix].state = -1;
806         dump_files[ix].flags = flags;
807
808         return 1;
809       }
810   return 0;
811 }