OSDN Git Service

libunwind related patch from David Mosberger
[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 (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           /* These nodes are handled explicitly below.  */
306           break;
307
308         default:
309           abort ();
310         }
311     }
312   else if (DECL_P (t))
313     {
314       /* All declarations have names.  */
315       if (DECL_NAME (t))
316         dump_child ("name", DECL_NAME (t));
317       if (DECL_ASSEMBLER_NAME_SET_P (t)
318           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
319         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
320       /* And types.  */
321       queue_and_dump_type (di, t);
322       dump_child ("scpe", DECL_CONTEXT (t));
323       /* And a source position.  */
324       if (DECL_SOURCE_FILE (t))
325         {
326           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
327           if (!filename)
328             filename = DECL_SOURCE_FILE (t);
329           else
330             /* Skip the slash.  */
331             ++filename;
332
333           dump_maybe_newline (di);
334           fprintf (di->stream, "srcp: %s:%-6d ", filename,
335                    DECL_SOURCE_LINE (t));
336           di->column += 6 + strlen (filename) + 8;
337         }
338       /* And any declaration can be compiler-generated.  */
339       if (DECL_ARTIFICIAL (t))
340         dump_string (di, "artificial");
341       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
342         dump_child ("chan", TREE_CHAIN (t));
343     }
344   else if (code_class == 't')
345     {
346       /* All types have qualifiers.  */
347       int quals = (*lang_hooks.tree_dump.type_quals) (t);
348
349       if (quals != TYPE_UNQUALIFIED)
350         {
351           fprintf (di->stream, "qual: %c%c%c     ",
352                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
353                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
354                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
355           di->column += 14;
356         }
357
358       /* All types have associated declarations.  */
359       dump_child ("name", TYPE_NAME (t));
360
361       /* All types have a main variant.  */
362       if (TYPE_MAIN_VARIANT (t) != t)
363         dump_child ("unql", TYPE_MAIN_VARIANT (t));
364
365       /* And sizes.  */
366       dump_child ("size", TYPE_SIZE (t));
367
368       /* All types have alignments.  */
369       dump_int (di, "algn", TYPE_ALIGN (t));
370     }
371   else if (code_class == 'c')
372     /* All constants can have types.  */
373     queue_and_dump_type (di, t);
374
375   /* Give the language-specific code a chance to print something.  If
376      it's completely taken care of things, don't bother printing
377      anything more ourselves.  */
378   if ((*lang_hooks.tree_dump.dump_tree) (di, t))
379     goto done;
380
381   /* Now handle the various kinds of nodes.  */
382   switch (code)
383     {
384       int i;
385
386     case IDENTIFIER_NODE:
387       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
388       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
389       break;
390
391     case TREE_LIST:
392       dump_child ("purp", TREE_PURPOSE (t));
393       dump_child ("valu", TREE_VALUE (t));
394       dump_child ("chan", TREE_CHAIN (t));
395       break;
396
397     case TREE_VEC:
398       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
399       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
400         {
401           char buffer[32];
402           sprintf (buffer, "%u", i);
403           dump_child (buffer, TREE_VEC_ELT (t, i));
404         }
405       break;
406
407     case INTEGER_TYPE:
408     case ENUMERAL_TYPE:
409       dump_int (di, "prec", TYPE_PRECISION (t));
410       if (TREE_UNSIGNED (t))
411         dump_string (di, "unsigned");
412       dump_child ("min", TYPE_MIN_VALUE (t));
413       dump_child ("max", TYPE_MAX_VALUE (t));
414
415       if (code == ENUMERAL_TYPE)
416         dump_child ("csts", TYPE_VALUES (t));
417       break;
418
419     case REAL_TYPE:
420       dump_int (di, "prec", TYPE_PRECISION (t));
421       break;
422
423     case POINTER_TYPE:
424       dump_child ("ptd", TREE_TYPE (t));
425       break;
426
427     case REFERENCE_TYPE:
428       dump_child ("refd", TREE_TYPE (t));
429       break;
430
431     case METHOD_TYPE:
432       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
433       /* Fall through.  */
434
435     case FUNCTION_TYPE:
436       dump_child ("retn", TREE_TYPE (t));
437       dump_child ("prms", TYPE_ARG_TYPES (t));
438       break;
439
440     case ARRAY_TYPE:
441       dump_child ("elts", TREE_TYPE (t));
442       dump_child ("domn", TYPE_DOMAIN (t));
443       break;
444
445     case RECORD_TYPE:
446     case UNION_TYPE:
447       if (TREE_CODE (t) == RECORD_TYPE)
448         dump_string (di, "struct");
449       else
450         dump_string (di, "union");
451
452       dump_child ("flds", TYPE_FIELDS (t));
453       dump_child ("fncs", TYPE_METHODS (t));
454       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
455                             DUMP_BINFO);
456       break;
457
458     case CONST_DECL:
459       dump_child ("cnst", DECL_INITIAL (t));
460       break;
461
462     case VAR_DECL:
463     case PARM_DECL:
464     case FIELD_DECL:
465     case RESULT_DECL:
466       if (TREE_CODE (t) == PARM_DECL)
467         dump_child ("argt", DECL_ARG_TYPE (t));
468       else
469         dump_child ("init", DECL_INITIAL (t));
470       dump_child ("size", DECL_SIZE (t));
471       dump_int (di, "algn", DECL_ALIGN (t));
472
473       if (TREE_CODE (t) == FIELD_DECL)
474         {
475           if (DECL_FIELD_OFFSET (t))
476             dump_child ("bpos", bit_position (t));
477         }
478       else if (TREE_CODE (t) == VAR_DECL
479                || TREE_CODE (t) == PARM_DECL)
480         {
481           dump_int (di, "used", TREE_USED (t));
482           if (DECL_REGISTER (t))
483             dump_string (di, "register");
484         }
485       break;
486
487     case FUNCTION_DECL:
488       dump_child ("args", DECL_ARGUMENTS (t));
489       if (DECL_EXTERNAL (t))
490         dump_string (di, "undefined");
491       if (TREE_PUBLIC (t))
492         dump_string (di, "extern");
493       else
494         dump_string (di, "static");
495       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
496         dump_child ("body", DECL_SAVED_TREE (t));
497       break;
498
499     case INTEGER_CST:
500       if (TREE_INT_CST_HIGH (t))
501         dump_int (di, "high", TREE_INT_CST_HIGH (t));
502       dump_int (di, "low", TREE_INT_CST_LOW (t));
503       break;
504
505     case STRING_CST:
506       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
507       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
508       break;
509
510     case TRUTH_NOT_EXPR:
511     case ADDR_EXPR:
512     case INDIRECT_REF:
513     case CLEANUP_POINT_EXPR:
514     case SAVE_EXPR:
515       /* These nodes are unary, but do not have code class `1'.  */
516       dump_child ("op 0", TREE_OPERAND (t, 0));
517       break;
518
519     case TRUTH_ANDIF_EXPR:
520     case TRUTH_ORIF_EXPR:
521     case INIT_EXPR:
522     case MODIFY_EXPR:
523     case COMPONENT_REF:
524     case COMPOUND_EXPR:
525     case ARRAY_REF:
526     case PREDECREMENT_EXPR:
527     case PREINCREMENT_EXPR:
528     case POSTDECREMENT_EXPR:
529     case POSTINCREMENT_EXPR:
530       /* These nodes are binary, but do not have code class `2'.  */
531       dump_child ("op 0", TREE_OPERAND (t, 0));
532       dump_child ("op 1", TREE_OPERAND (t, 1));
533       break;
534
535     case COND_EXPR:
536       dump_child ("op 0", TREE_OPERAND (t, 0));
537       dump_child ("op 1", TREE_OPERAND (t, 1));
538       dump_child ("op 2", TREE_OPERAND (t, 2));
539       break;
540
541     case CALL_EXPR:
542       dump_child ("fn", TREE_OPERAND (t, 0));
543       dump_child ("args", TREE_OPERAND (t, 1));
544       break;
545
546     case CONSTRUCTOR:
547       dump_child ("elts", CONSTRUCTOR_ELTS (t));
548       break;
549
550     case BIND_EXPR:
551       dump_child ("vars", TREE_OPERAND (t, 0));
552       dump_child ("body", TREE_OPERAND (t, 1));
553       break;
554
555     case LOOP_EXPR:
556       dump_child ("body", TREE_OPERAND (t, 0));
557       break;
558
559     case EXIT_EXPR:
560       dump_child ("cond", TREE_OPERAND (t, 0));
561       break;
562
563     case TARGET_EXPR:
564       dump_child ("decl", TREE_OPERAND (t, 0));
565       dump_child ("init", TREE_OPERAND (t, 1));
566       dump_child ("clnp", TREE_OPERAND (t, 2));
567       /* There really are two possible places the initializer can be.
568          After RTL expansion, the second operand is moved to the
569          position of the fourth operand, and the second operand
570          becomes NULL.  */
571       dump_child ("init", TREE_OPERAND (t, 3));
572       break;
573
574     case EXPR_WITH_FILE_LOCATION:
575       dump_child ("expr", EXPR_WFL_NODE (t));
576       break;
577
578     default:
579       /* There are no additional fields to print.  */
580       break;
581     }
582
583  done:
584   if (dump_flag (di, TDF_ADDRESS, NULL))
585     dump_pointer (di, "addr", (void *)t);
586
587   /* Terminate the line.  */
588   fprintf (di->stream, "\n");
589 }
590
591 /* Return nonzero if FLAG has been specified for the dump, and NODE
592    is not the root node of the dump.  */
593
594 int dump_flag (dump_info_p di, int flag, tree node)
595 {
596   return (di->flags & flag) && (node != di->node);
597 }
598
599 /* Dump T, and all its children, on STREAM.  */
600
601 void
602 dump_node (tree t, int flags, FILE *stream)
603 {
604   struct dump_info di;
605   dump_queue_p dq;
606   dump_queue_p next_dq;
607
608   /* Initialize the dump-information structure.  */
609   di.stream = stream;
610   di.index = 0;
611   di.column = 0;
612   di.queue = 0;
613   di.queue_end = 0;
614   di.free_list = 0;
615   di.flags = flags;
616   di.node = t;
617   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
618                              (splay_tree_delete_value_fn) &free);
619
620   /* Queue up the first node.  */
621   queue (&di, t, DUMP_NONE);
622
623   /* Until the queue is empty, keep dumping nodes.  */
624   while (di.queue)
625     dequeue_and_dump (&di);
626
627   /* Now, clean up.  */
628   for (dq = di.free_list; dq; dq = next_dq)
629     {
630       next_dq = dq->next;
631       free (dq);
632     }
633   splay_tree_delete (di.nodes);
634 }
635
636 /* Define a tree dump switch.  */
637 struct dump_file_info
638 {
639   const char *const suffix;     /* suffix to give output file.  */
640   const char *const swtch;      /* command line switch */
641   int flags;                    /* user flags */
642   int state;                    /* state of play */
643 };
644
645 /* Table of tree dump switches. This must be consistent with the
646    TREE_DUMP_INDEX enumeration in tree.h */
647 static struct dump_file_info dump_files[TDI_end] =
648 {
649   {".tu", "translation-unit", 0, 0},
650   {".class", "class-hierarchy", 0, 0},
651   {".original", "tree-original", 0, 0},
652   {".optimized", "tree-optimized", 0, 0},
653   {".inlined", "tree-inlined", 0, 0},
654 };
655
656 /* Define a name->number mapping for a dump flag value.  */
657 struct dump_option_value_info
658 {
659   const char *const name;       /* the name of the value */
660   const int value;              /* the value of the name */
661 };
662
663 /* Table of dump options. This must be consistent with the TDF_* flags
664    in tree.h */
665 static const struct dump_option_value_info dump_options[] =
666 {
667   {"address", TDF_ADDRESS},
668   {"slim", TDF_SLIM},
669   {"all", ~0},
670   {NULL, 0}
671 };
672
673 /* Begin a tree dump for PHASE. Stores any user supplied flag in
674    *FLAG_PTR and returns a stream to write to. If the dump is not
675    enabled, returns NULL.
676    Multiple calls will reopen and append to the dump file.  */
677
678 FILE *
679 dump_begin (enum tree_dump_index phase, int *flag_ptr)
680 {
681   FILE *stream;
682   char *name;
683
684   if (!dump_files[phase].state)
685     return NULL;
686
687   name = concat (dump_base_name, dump_files[phase].suffix, NULL);
688   stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
689   if (!stream)
690     error ("could not open dump file `%s'", name);
691   else
692     dump_files[phase].state = 1;
693   free (name);
694   if (flag_ptr)
695     *flag_ptr = dump_files[phase].flags;
696
697   return stream;
698 }
699
700 /* Returns nonzero if tree dump PHASE is enabled.  */
701
702 int
703 dump_enabled_p (enum tree_dump_index phase)
704 {
705   return dump_files[phase].state;
706 }
707
708 /* Returns the switch name of PHASE.  */
709
710 const char *
711 dump_flag_name (enum tree_dump_index phase)
712 {
713   return dump_files[phase].swtch;
714 }
715
716 /* Finish a tree dump for PHASE. STREAM is the stream created by
717    dump_begin.  */
718
719 void
720 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
721 {
722   fclose (stream);
723 }
724
725 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
726    relevant details in the dump_files array.  */
727
728 int
729 dump_switch_p (const char *arg)
730 {
731   unsigned ix;
732   const char *option_value;
733
734   for (ix = 0; ix != TDI_end; ix++)
735     if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
736       {
737         const char *ptr = option_value;
738         int flags = 0;
739
740         while (*ptr)
741           {
742             const struct dump_option_value_info *option_ptr;
743             const char *end_ptr;
744             unsigned length;
745
746             while (*ptr == '-')
747               ptr++;
748             end_ptr = strchr (ptr, '-');
749             if (!end_ptr)
750               end_ptr = ptr + strlen (ptr);
751             length = end_ptr - ptr;
752
753             for (option_ptr = dump_options; option_ptr->name;
754                  option_ptr++)
755               if (strlen (option_ptr->name) == length
756                   && !memcmp (option_ptr->name, ptr, length))
757                 {
758                   flags |= option_ptr->value;
759                   goto found;
760                 }
761             warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
762                      length, ptr, dump_files[ix].swtch);
763           found:;
764             ptr = end_ptr;
765           }
766
767         dump_files[ix].state = -1;
768         dump_files[ix].flags = flags;
769
770         return 1;
771       }
772   return 0;
773 }