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