tree-dump.c revision 132718
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
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-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
33static unsigned int queue (dump_info_p, tree, int);
34static void dump_index (dump_info_p, unsigned int);
35static void dequeue_and_dump (dump_info_p);
36static void dump_new_line (dump_info_p);
37static void dump_maybe_newline (dump_info_p);
38static 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
43static unsigned int
44queue (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
81static void
82dump_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
92void
93queue_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
120void
121queue_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
134static void
135dump_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
143static void
144dump_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
161void
162dump_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
171void
172dump_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
181void
182dump_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
194static void
195dump_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
207static void
208dequeue_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
596int 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
603void
604dump_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.  */
639struct 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 */
649static 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.  */
659struct 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 */
667static 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
680FILE *
681dump_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
704int
705dump_enabled_p (enum tree_dump_index phase)
706{
707  return dump_files[phase].state;
708}
709
710/* Returns the switch name of PHASE.  */
711
712const char *
713dump_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
721void
722dump_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
730int
731dump_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}
776