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