0
|
1 /* Tree-dumping functionality for intermediate representation.
|
|
2 Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008
|
|
3 Free Software Foundation, Inc.
|
|
4 Written by Mark Mitchell <mark@codesourcery.com>
|
|
5
|
|
6 This file is part of GCC.
|
|
7
|
|
8 GCC is free software; you can redistribute it and/or modify it under
|
|
9 the terms of the GNU General Public License as published by the Free
|
|
10 Software Foundation; either version 3, or (at your option) any later
|
|
11 version.
|
|
12
|
|
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
16 for more details.
|
|
17
|
|
18 You should have received a copy of the GNU General Public License
|
|
19 along with GCC; see the file COPYING3. If not see
|
|
20 <http://www.gnu.org/licenses/>. */
|
|
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 "tree-pass.h"
|
|
32 #include "langhooks.h"
|
|
33 #include "tree-iterator.h"
|
|
34 #include "real.h"
|
|
35 #include "fixed-value.h"
|
|
36
|
|
37 static unsigned int queue (dump_info_p, const_tree, int);
|
|
38 static void dump_index (dump_info_p, unsigned int);
|
|
39 static void dequeue_and_dump (dump_info_p);
|
|
40 static void dump_new_line (dump_info_p);
|
|
41 static void dump_maybe_newline (dump_info_p);
|
|
42
|
|
43 /* Add T to the end of the queue of nodes to dump. Returns the index
|
|
44 assigned to T. */
|
|
45
|
|
46 static unsigned int
|
|
47 queue (dump_info_p di, const_tree t, 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 = XNEW (struct dump_queue);
|
|
64
|
|
65 /* Create a new entry in the splay-tree. */
|
|
66 dni = XNEW (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 (dump_info_p di, unsigned int index)
|
|
86 {
|
|
87 fprintf (di->stream, "@%-6u ", index);
|
|
88 di->column += 8;
|
|
89 }
|
|
90
|
|
91 /* If T has not already been output, queue it for subsequent output.
|
|
92 FIELD is a string to print before printing the index. Then, the
|
|
93 index of T is printed. */
|
|
94
|
|
95 void
|
|
96 queue_and_dump_index (dump_info_p di, const char *field, const_tree t, int flags)
|
|
97 {
|
|
98 unsigned int index;
|
|
99 splay_tree_node n;
|
|
100
|
|
101 /* If there's no node, just return. This makes for fewer checks in
|
|
102 our callers. */
|
|
103 if (!t)
|
|
104 return;
|
|
105
|
|
106 /* See if we've already queued or dumped this node. */
|
|
107 n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
|
|
108 if (n)
|
|
109 index = ((dump_node_info_p) n->value)->index;
|
|
110 else
|
|
111 /* If we haven't, add it to the queue. */
|
|
112 index = queue (di, t, flags);
|
|
113
|
|
114 /* Print the index of the node. */
|
|
115 dump_maybe_newline (di);
|
|
116 fprintf (di->stream, "%-4s: ", field);
|
|
117 di->column += 6;
|
|
118 dump_index (di, index);
|
|
119 }
|
|
120
|
|
121 /* Dump the type of T. */
|
|
122
|
|
123 void
|
|
124 queue_and_dump_type (dump_info_p di, const_tree t)
|
|
125 {
|
|
126 queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
|
|
127 }
|
|
128
|
|
129 /* Dump column control */
|
|
130 #define SOL_COLUMN 25 /* Start of line column. */
|
|
131 #define EOL_COLUMN 55 /* End of line column. */
|
|
132 #define COLUMN_ALIGNMENT 15 /* Alignment. */
|
|
133
|
|
134 /* Insert a new line in the dump output, and indent to an appropriate
|
|
135 place to start printing more fields. */
|
|
136
|
|
137 static void
|
|
138 dump_new_line (dump_info_p di)
|
|
139 {
|
|
140 fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
|
|
141 di->column = SOL_COLUMN;
|
|
142 }
|
|
143
|
|
144 /* If necessary, insert a new line. */
|
|
145
|
|
146 static void
|
|
147 dump_maybe_newline (dump_info_p di)
|
|
148 {
|
|
149 int extra;
|
|
150
|
|
151 /* See if we need a new line. */
|
|
152 if (di->column > EOL_COLUMN)
|
|
153 dump_new_line (di);
|
|
154 /* See if we need any padding. */
|
|
155 else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
|
|
156 {
|
|
157 fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
|
|
158 di->column += COLUMN_ALIGNMENT - extra;
|
|
159 }
|
|
160 }
|
|
161
|
|
162 /* Dump pointer PTR using FIELD to identify it. */
|
|
163
|
|
164 void
|
|
165 dump_pointer (dump_info_p di, const char *field, void *ptr)
|
|
166 {
|
|
167 dump_maybe_newline (di);
|
|
168 fprintf (di->stream, "%-4s: %-8lx ", field, (unsigned long) ptr);
|
|
169 di->column += 15;
|
|
170 }
|
|
171
|
|
172 /* Dump integer I using FIELD to identify it. */
|
|
173
|
|
174 void
|
|
175 dump_int (dump_info_p di, const char *field, int i)
|
|
176 {
|
|
177 dump_maybe_newline (di);
|
|
178 fprintf (di->stream, "%-4s: %-7d ", field, i);
|
|
179 di->column += 14;
|
|
180 }
|
|
181
|
|
182 /* Dump the floating point value R, using FIELD to identify it. */
|
|
183
|
|
184 static void
|
|
185 dump_real (dump_info_p di, const char *field, const REAL_VALUE_TYPE *r)
|
|
186 {
|
|
187 char buf[32];
|
|
188 real_to_decimal (buf, r, sizeof (buf), 0, true);
|
|
189 dump_maybe_newline (di);
|
|
190 fprintf (di->stream, "%-4s: %s ", field, buf);
|
|
191 di->column += strlen (buf) + 7;
|
|
192 }
|
|
193
|
|
194 /* Dump the fixed-point value F, using FIELD to identify it. */
|
|
195
|
|
196 static void
|
|
197 dump_fixed (dump_info_p di, const char *field, const FIXED_VALUE_TYPE *f)
|
|
198 {
|
|
199 char buf[32];
|
|
200 fixed_to_decimal (buf, f, sizeof (buf));
|
|
201 dump_maybe_newline (di);
|
|
202 fprintf (di->stream, "%-4s: %s ", field, buf);
|
|
203 di->column += strlen (buf) + 7;
|
|
204 }
|
|
205
|
|
206
|
|
207 /* Dump the string S. */
|
|
208
|
|
209 void
|
|
210 dump_string (dump_info_p di, const char *string)
|
|
211 {
|
|
212 dump_maybe_newline (di);
|
|
213 fprintf (di->stream, "%-13s ", string);
|
|
214 if (strlen (string) > 13)
|
|
215 di->column += strlen (string) + 1;
|
|
216 else
|
|
217 di->column += 14;
|
|
218 }
|
|
219
|
|
220 /* Dump the string field S. */
|
|
221
|
|
222 void
|
|
223 dump_string_field (dump_info_p di, const char *field, const char *string)
|
|
224 {
|
|
225 dump_maybe_newline (di);
|
|
226 fprintf (di->stream, "%-4s: %-7s ", field, string);
|
|
227 if (strlen (string) > 7)
|
|
228 di->column += 6 + strlen (string) + 1;
|
|
229 else
|
|
230 di->column += 14;
|
|
231 }
|
|
232
|
|
233 /* Dump the next node in the queue. */
|
|
234
|
|
235 static void
|
|
236 dequeue_and_dump (dump_info_p di)
|
|
237 {
|
|
238 dump_queue_p dq;
|
|
239 splay_tree_node stn;
|
|
240 dump_node_info_p dni;
|
|
241 tree t;
|
|
242 unsigned int index;
|
|
243 enum tree_code code;
|
|
244 enum tree_code_class code_class;
|
|
245 const char* code_name;
|
|
246
|
|
247 /* Get the next node from the queue. */
|
|
248 dq = di->queue;
|
|
249 stn = dq->node;
|
|
250 t = (tree) stn->key;
|
|
251 dni = (dump_node_info_p) stn->value;
|
|
252 index = dni->index;
|
|
253
|
|
254 /* Remove the node from the queue, and put it on the free list. */
|
|
255 di->queue = dq->next;
|
|
256 if (!di->queue)
|
|
257 di->queue_end = 0;
|
|
258 dq->next = di->free_list;
|
|
259 di->free_list = dq;
|
|
260
|
|
261 /* Print the node index. */
|
|
262 dump_index (di, index);
|
|
263 /* And the type of node this is. */
|
|
264 if (dni->binfo_p)
|
|
265 code_name = "binfo";
|
|
266 else
|
|
267 code_name = tree_code_name[(int) TREE_CODE (t)];
|
|
268 fprintf (di->stream, "%-16s ", code_name);
|
|
269 di->column = 25;
|
|
270
|
|
271 /* Figure out what kind of node this is. */
|
|
272 code = TREE_CODE (t);
|
|
273 code_class = TREE_CODE_CLASS (code);
|
|
274
|
|
275 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
|
|
276 more informative. */
|
|
277 if (dni->binfo_p)
|
|
278 {
|
|
279 unsigned ix;
|
|
280 tree base;
|
|
281 VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);
|
|
282
|
|
283 dump_child ("type", BINFO_TYPE (t));
|
|
284
|
|
285 if (BINFO_VIRTUAL_P (t))
|
|
286 dump_string_field (di, "spec", "virt");
|
|
287
|
|
288 dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
|
|
289 for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
|
|
290 {
|
|
291 tree access = (accesses ? VEC_index (tree, accesses, ix)
|
|
292 : access_public_node);
|
|
293 const char *string = NULL;
|
|
294
|
|
295 if (access == access_public_node)
|
|
296 string = "pub";
|
|
297 else if (access == access_protected_node)
|
|
298 string = "prot";
|
|
299 else if (access == access_private_node)
|
|
300 string = "priv";
|
|
301 else
|
|
302 gcc_unreachable ();
|
|
303
|
|
304 dump_string_field (di, "accs", string);
|
|
305 queue_and_dump_index (di, "binf", base, DUMP_BINFO);
|
|
306 }
|
|
307
|
|
308 goto done;
|
|
309 }
|
|
310
|
|
311 /* We can knock off a bunch of expression nodes in exactly the same
|
|
312 way. */
|
|
313 if (IS_EXPR_CODE_CLASS (code_class))
|
|
314 {
|
|
315 /* If we're dumping children, dump them now. */
|
|
316 queue_and_dump_type (di, t);
|
|
317
|
|
318 switch (code_class)
|
|
319 {
|
|
320 case tcc_unary:
|
|
321 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
322 break;
|
|
323
|
|
324 case tcc_binary:
|
|
325 case tcc_comparison:
|
|
326 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
327 dump_child ("op 1", TREE_OPERAND (t, 1));
|
|
328 break;
|
|
329
|
|
330 case tcc_expression:
|
|
331 case tcc_reference:
|
|
332 case tcc_statement:
|
|
333 case tcc_vl_exp:
|
|
334 /* These nodes are handled explicitly below. */
|
|
335 break;
|
|
336
|
|
337 default:
|
|
338 gcc_unreachable ();
|
|
339 }
|
|
340 }
|
|
341 else if (DECL_P (t))
|
|
342 {
|
|
343 expanded_location xloc;
|
|
344 /* All declarations have names. */
|
|
345 if (DECL_NAME (t))
|
|
346 dump_child ("name", DECL_NAME (t));
|
|
347 if (DECL_ASSEMBLER_NAME_SET_P (t)
|
|
348 && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
|
|
349 dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
|
|
350 if (DECL_ABSTRACT_ORIGIN (t))
|
|
351 dump_child ("orig", DECL_ABSTRACT_ORIGIN (t));
|
|
352 /* And types. */
|
|
353 queue_and_dump_type (di, t);
|
|
354 dump_child ("scpe", DECL_CONTEXT (t));
|
|
355 /* And a source position. */
|
|
356 xloc = expand_location (DECL_SOURCE_LOCATION (t));
|
|
357 if (xloc.file)
|
|
358 {
|
|
359 const char *filename = strrchr (xloc.file, '/');
|
|
360 if (!filename)
|
|
361 filename = xloc.file;
|
|
362 else
|
|
363 /* Skip the slash. */
|
|
364 ++filename;
|
|
365
|
|
366 dump_maybe_newline (di);
|
|
367 fprintf (di->stream, "srcp: %s:%-6d ", filename,
|
|
368 xloc.line);
|
|
369 di->column += 6 + strlen (filename) + 8;
|
|
370 }
|
|
371 /* And any declaration can be compiler-generated. */
|
|
372 if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON)
|
|
373 && DECL_ARTIFICIAL (t))
|
|
374 dump_string_field (di, "note", "artificial");
|
|
375 if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
|
|
376 dump_child ("chan", TREE_CHAIN (t));
|
|
377 }
|
|
378 else if (code_class == tcc_type)
|
|
379 {
|
|
380 /* All types have qualifiers. */
|
|
381 int quals = lang_hooks.tree_dump.type_quals (t);
|
|
382
|
|
383 if (quals != TYPE_UNQUALIFIED)
|
|
384 {
|
|
385 fprintf (di->stream, "qual: %c%c%c ",
|
|
386 (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
|
|
387 (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
|
|
388 (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
|
|
389 di->column += 14;
|
|
390 }
|
|
391
|
|
392 /* All types have associated declarations. */
|
|
393 dump_child ("name", TYPE_NAME (t));
|
|
394
|
|
395 /* All types have a main variant. */
|
|
396 if (TYPE_MAIN_VARIANT (t) != t)
|
|
397 dump_child ("unql", TYPE_MAIN_VARIANT (t));
|
|
398
|
|
399 /* And sizes. */
|
|
400 dump_child ("size", TYPE_SIZE (t));
|
|
401
|
|
402 /* All types have alignments. */
|
|
403 dump_int (di, "algn", TYPE_ALIGN (t));
|
|
404 }
|
|
405 else if (code_class == tcc_constant)
|
|
406 /* All constants can have types. */
|
|
407 queue_and_dump_type (di, t);
|
|
408
|
|
409 /* Give the language-specific code a chance to print something. If
|
|
410 it's completely taken care of things, don't bother printing
|
|
411 anything more ourselves. */
|
|
412 if (lang_hooks.tree_dump.dump_tree (di, t))
|
|
413 goto done;
|
|
414
|
|
415 /* Now handle the various kinds of nodes. */
|
|
416 switch (code)
|
|
417 {
|
|
418 int i;
|
|
419
|
|
420 case IDENTIFIER_NODE:
|
|
421 dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
|
|
422 dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
|
|
423 break;
|
|
424
|
|
425 case TREE_LIST:
|
|
426 dump_child ("purp", TREE_PURPOSE (t));
|
|
427 dump_child ("valu", TREE_VALUE (t));
|
|
428 dump_child ("chan", TREE_CHAIN (t));
|
|
429 break;
|
|
430
|
|
431 case STATEMENT_LIST:
|
|
432 {
|
|
433 tree_stmt_iterator it;
|
|
434 for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
|
|
435 {
|
|
436 char buffer[32];
|
|
437 sprintf (buffer, "%u", i);
|
|
438 dump_child (buffer, tsi_stmt (it));
|
|
439 }
|
|
440 }
|
|
441 break;
|
|
442
|
|
443 case TREE_VEC:
|
|
444 dump_int (di, "lngt", TREE_VEC_LENGTH (t));
|
|
445 for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
|
|
446 {
|
|
447 char buffer[32];
|
|
448 sprintf (buffer, "%u", i);
|
|
449 dump_child (buffer, TREE_VEC_ELT (t, i));
|
|
450 }
|
|
451 break;
|
|
452
|
|
453 case INTEGER_TYPE:
|
|
454 case ENUMERAL_TYPE:
|
|
455 dump_int (di, "prec", TYPE_PRECISION (t));
|
|
456 dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
|
|
457 dump_child ("min", TYPE_MIN_VALUE (t));
|
|
458 dump_child ("max", TYPE_MAX_VALUE (t));
|
|
459
|
|
460 if (code == ENUMERAL_TYPE)
|
|
461 dump_child ("csts", TYPE_VALUES (t));
|
|
462 break;
|
|
463
|
|
464 case REAL_TYPE:
|
|
465 dump_int (di, "prec", TYPE_PRECISION (t));
|
|
466 break;
|
|
467
|
|
468 case FIXED_POINT_TYPE:
|
|
469 dump_int (di, "prec", TYPE_PRECISION (t));
|
|
470 dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
|
|
471 dump_string_field (di, "saturating",
|
|
472 TYPE_SATURATING (t) ? "saturating": "non-saturating");
|
|
473 break;
|
|
474
|
|
475 case POINTER_TYPE:
|
|
476 dump_child ("ptd", TREE_TYPE (t));
|
|
477 break;
|
|
478
|
|
479 case REFERENCE_TYPE:
|
|
480 dump_child ("refd", TREE_TYPE (t));
|
|
481 break;
|
|
482
|
|
483 case METHOD_TYPE:
|
|
484 dump_child ("clas", TYPE_METHOD_BASETYPE (t));
|
|
485 /* Fall through. */
|
|
486
|
|
487 case FUNCTION_TYPE:
|
|
488 dump_child ("retn", TREE_TYPE (t));
|
|
489 dump_child ("prms", TYPE_ARG_TYPES (t));
|
|
490 break;
|
|
491
|
|
492 case ARRAY_TYPE:
|
|
493 dump_child ("elts", TREE_TYPE (t));
|
|
494 dump_child ("domn", TYPE_DOMAIN (t));
|
|
495 break;
|
|
496
|
|
497 case RECORD_TYPE:
|
|
498 case UNION_TYPE:
|
|
499 if (TREE_CODE (t) == RECORD_TYPE)
|
|
500 dump_string_field (di, "tag", "struct");
|
|
501 else
|
|
502 dump_string_field (di, "tag", "union");
|
|
503
|
|
504 dump_child ("flds", TYPE_FIELDS (t));
|
|
505 dump_child ("fncs", TYPE_METHODS (t));
|
|
506 queue_and_dump_index (di, "binf", TYPE_BINFO (t),
|
|
507 DUMP_BINFO);
|
|
508 break;
|
|
509
|
|
510 case CONST_DECL:
|
|
511 dump_child ("cnst", DECL_INITIAL (t));
|
|
512 break;
|
|
513
|
|
514 case SYMBOL_MEMORY_TAG:
|
|
515 case NAME_MEMORY_TAG:
|
|
516 break;
|
|
517
|
|
518 case VAR_DECL:
|
|
519 case PARM_DECL:
|
|
520 case FIELD_DECL:
|
|
521 case RESULT_DECL:
|
|
522 if (TREE_CODE (t) == PARM_DECL)
|
|
523 dump_child ("argt", DECL_ARG_TYPE (t));
|
|
524 else
|
|
525 dump_child ("init", DECL_INITIAL (t));
|
|
526 dump_child ("size", DECL_SIZE (t));
|
|
527 dump_int (di, "algn", DECL_ALIGN (t));
|
|
528
|
|
529 if (TREE_CODE (t) == FIELD_DECL)
|
|
530 {
|
|
531 if (DECL_FIELD_OFFSET (t))
|
|
532 dump_child ("bpos", bit_position (t));
|
|
533 }
|
|
534 else if (TREE_CODE (t) == VAR_DECL
|
|
535 || TREE_CODE (t) == PARM_DECL)
|
|
536 {
|
|
537 dump_int (di, "used", TREE_USED (t));
|
|
538 if (DECL_REGISTER (t))
|
|
539 dump_string_field (di, "spec", "register");
|
|
540 }
|
|
541 break;
|
|
542
|
|
543 case FUNCTION_DECL:
|
|
544 dump_child ("args", DECL_ARGUMENTS (t));
|
|
545 if (DECL_EXTERNAL (t))
|
|
546 dump_string_field (di, "body", "undefined");
|
|
547 if (TREE_PUBLIC (t))
|
|
548 dump_string_field (di, "link", "extern");
|
|
549 else
|
|
550 dump_string_field (di, "link", "static");
|
|
551 if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t))
|
|
552 dump_child ("body", DECL_SAVED_TREE (t));
|
|
553 break;
|
|
554
|
|
555 case INTEGER_CST:
|
|
556 if (TREE_INT_CST_HIGH (t))
|
|
557 dump_int (di, "high", TREE_INT_CST_HIGH (t));
|
|
558 dump_int (di, "low", TREE_INT_CST_LOW (t));
|
|
559 break;
|
|
560
|
|
561 case STRING_CST:
|
|
562 fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
|
|
563 dump_int (di, "lngt", TREE_STRING_LENGTH (t));
|
|
564 break;
|
|
565
|
|
566 case REAL_CST:
|
|
567 dump_real (di, "valu", TREE_REAL_CST_PTR (t));
|
|
568 break;
|
|
569
|
|
570 case FIXED_CST:
|
|
571 dump_fixed (di, "valu", TREE_FIXED_CST_PTR (t));
|
|
572 break;
|
|
573
|
|
574 case TRUTH_NOT_EXPR:
|
|
575 case ADDR_EXPR:
|
|
576 case INDIRECT_REF:
|
|
577 case ALIGN_INDIRECT_REF:
|
|
578 case MISALIGNED_INDIRECT_REF:
|
|
579 case CLEANUP_POINT_EXPR:
|
|
580 case SAVE_EXPR:
|
|
581 case REALPART_EXPR:
|
|
582 case IMAGPART_EXPR:
|
|
583 /* These nodes are unary, but do not have code class `1'. */
|
|
584 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
585 break;
|
|
586
|
|
587 case TRUTH_ANDIF_EXPR:
|
|
588 case TRUTH_ORIF_EXPR:
|
|
589 case INIT_EXPR:
|
|
590 case MODIFY_EXPR:
|
|
591 case COMPOUND_EXPR:
|
|
592 case PREDECREMENT_EXPR:
|
|
593 case PREINCREMENT_EXPR:
|
|
594 case POSTDECREMENT_EXPR:
|
|
595 case POSTINCREMENT_EXPR:
|
|
596 /* These nodes are binary, but do not have code class `2'. */
|
|
597 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
598 dump_child ("op 1", TREE_OPERAND (t, 1));
|
|
599 break;
|
|
600
|
|
601 case COMPONENT_REF:
|
|
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 ARRAY_REF:
|
|
608 case ARRAY_RANGE_REF:
|
|
609 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
610 dump_child ("op 1", TREE_OPERAND (t, 1));
|
|
611 dump_child ("op 2", TREE_OPERAND (t, 2));
|
|
612 dump_child ("op 3", TREE_OPERAND (t, 3));
|
|
613 break;
|
|
614
|
|
615 case COND_EXPR:
|
|
616 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
617 dump_child ("op 1", TREE_OPERAND (t, 1));
|
|
618 dump_child ("op 2", TREE_OPERAND (t, 2));
|
|
619 break;
|
|
620
|
|
621 case TRY_FINALLY_EXPR:
|
|
622 dump_child ("op 0", TREE_OPERAND (t, 0));
|
|
623 dump_child ("op 1", TREE_OPERAND (t, 1));
|
|
624 break;
|
|
625
|
|
626 case CALL_EXPR:
|
|
627 {
|
|
628 int i = 0;
|
|
629 tree arg;
|
|
630 call_expr_arg_iterator iter;
|
|
631 dump_child ("fn", CALL_EXPR_FN (t));
|
|
632 FOR_EACH_CALL_EXPR_ARG (arg, iter, t)
|
|
633 {
|
|
634 char buffer[32];
|
|
635 sprintf (buffer, "%u", i);
|
|
636 dump_child (buffer, arg);
|
|
637 i++;
|
|
638 }
|
|
639 }
|
|
640 break;
|
|
641
|
|
642 case CONSTRUCTOR:
|
|
643 {
|
|
644 unsigned HOST_WIDE_INT cnt;
|
|
645 tree index, value;
|
|
646 dump_int (di, "lngt", VEC_length (constructor_elt,
|
|
647 CONSTRUCTOR_ELTS (t)));
|
|
648 FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
|
|
649 {
|
|
650 dump_child ("idx", index);
|
|
651 dump_child ("val", value);
|
|
652 }
|
|
653 }
|
|
654 break;
|
|
655
|
|
656 case BIND_EXPR:
|
|
657 dump_child ("vars", TREE_OPERAND (t, 0));
|
|
658 dump_child ("body", TREE_OPERAND (t, 1));
|
|
659 break;
|
|
660
|
|
661 case LOOP_EXPR:
|
|
662 dump_child ("body", TREE_OPERAND (t, 0));
|
|
663 break;
|
|
664
|
|
665 case EXIT_EXPR:
|
|
666 dump_child ("cond", TREE_OPERAND (t, 0));
|
|
667 break;
|
|
668
|
|
669 case RETURN_EXPR:
|
|
670 dump_child ("expr", TREE_OPERAND (t, 0));
|
|
671 break;
|
|
672
|
|
673 case TARGET_EXPR:
|
|
674 dump_child ("decl", TREE_OPERAND (t, 0));
|
|
675 dump_child ("init", TREE_OPERAND (t, 1));
|
|
676 dump_child ("clnp", TREE_OPERAND (t, 2));
|
|
677 /* There really are two possible places the initializer can be.
|
|
678 After RTL expansion, the second operand is moved to the
|
|
679 position of the fourth operand, and the second operand
|
|
680 becomes NULL. */
|
|
681 dump_child ("init", TREE_OPERAND (t, 3));
|
|
682 break;
|
|
683
|
|
684 case CASE_LABEL_EXPR:
|
|
685 dump_child ("name", CASE_LABEL (t));
|
|
686 if (CASE_LOW (t))
|
|
687 {
|
|
688 dump_child ("low ", CASE_LOW (t));
|
|
689 if (CASE_HIGH (t))
|
|
690 dump_child ("high", CASE_HIGH (t));
|
|
691 }
|
|
692 break;
|
|
693 case LABEL_EXPR:
|
|
694 dump_child ("name", TREE_OPERAND (t,0));
|
|
695 break;
|
|
696 case GOTO_EXPR:
|
|
697 dump_child ("labl", TREE_OPERAND (t, 0));
|
|
698 break;
|
|
699 case SWITCH_EXPR:
|
|
700 dump_child ("cond", TREE_OPERAND (t, 0));
|
|
701 dump_child ("body", TREE_OPERAND (t, 1));
|
|
702 if (TREE_OPERAND (t, 2))
|
|
703 {
|
|
704 dump_child ("labl", TREE_OPERAND (t,2));
|
|
705 }
|
|
706 break;
|
|
707 case OMP_CLAUSE:
|
|
708 {
|
|
709 int i;
|
|
710 fprintf (di->stream, "%s\n", omp_clause_code_name[OMP_CLAUSE_CODE (t)]);
|
|
711 for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++)
|
|
712 dump_child ("op: ", OMP_CLAUSE_OPERAND (t, i));
|
|
713 }
|
|
714 break;
|
|
715 default:
|
|
716 /* There are no additional fields to print. */
|
|
717 break;
|
|
718 }
|
|
719
|
|
720 done:
|
|
721 if (dump_flag (di, TDF_ADDRESS, NULL))
|
|
722 dump_pointer (di, "addr", (void *)t);
|
|
723
|
|
724 /* Terminate the line. */
|
|
725 fprintf (di->stream, "\n");
|
|
726 }
|
|
727
|
|
728 /* Return nonzero if FLAG has been specified for the dump, and NODE
|
|
729 is not the root node of the dump. */
|
|
730
|
|
731 int dump_flag (dump_info_p di, int flag, const_tree node)
|
|
732 {
|
|
733 return (di->flags & flag) && (node != di->node);
|
|
734 }
|
|
735
|
|
736 /* Dump T, and all its children, on STREAM. */
|
|
737
|
|
738 void
|
|
739 dump_node (const_tree t, int flags, FILE *stream)
|
|
740 {
|
|
741 struct dump_info di;
|
|
742 dump_queue_p dq;
|
|
743 dump_queue_p next_dq;
|
|
744
|
|
745 /* Initialize the dump-information structure. */
|
|
746 di.stream = stream;
|
|
747 di.index = 0;
|
|
748 di.column = 0;
|
|
749 di.queue = 0;
|
|
750 di.queue_end = 0;
|
|
751 di.free_list = 0;
|
|
752 di.flags = flags;
|
|
753 di.node = t;
|
|
754 di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
|
|
755 (splay_tree_delete_value_fn) &free);
|
|
756
|
|
757 /* Queue up the first node. */
|
|
758 queue (&di, t, DUMP_NONE);
|
|
759
|
|
760 /* Until the queue is empty, keep dumping nodes. */
|
|
761 while (di.queue)
|
|
762 dequeue_and_dump (&di);
|
|
763
|
|
764 /* Now, clean up. */
|
|
765 for (dq = di.free_list; dq; dq = next_dq)
|
|
766 {
|
|
767 next_dq = dq->next;
|
|
768 free (dq);
|
|
769 }
|
|
770 splay_tree_delete (di.nodes);
|
|
771 }
|
|
772
|
|
773
|
|
774 /* Table of tree dump switches. This must be consistent with the
|
|
775 tree_dump_index enumeration in tree-pass.h. */
|
|
776 static struct dump_file_info dump_files[TDI_end] =
|
|
777 {
|
|
778 {NULL, NULL, NULL, 0, 0, 0},
|
|
779 {".cgraph", "ipa-cgraph", NULL, TDF_IPA, 0, 0},
|
|
780 {".tu", "translation-unit", NULL, TDF_TREE, 0, 1},
|
|
781 {".class", "class-hierarchy", NULL, TDF_TREE, 0, 2},
|
|
782 {".original", "tree-original", NULL, TDF_TREE, 0, 3},
|
|
783 {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 4},
|
|
784 {".nested", "tree-nested", NULL, TDF_TREE, 0, 5},
|
|
785 {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6},
|
|
786 #define FIRST_AUTO_NUMBERED_DUMP 7
|
|
787
|
|
788 {NULL, "tree-all", NULL, TDF_TREE, 0, 0},
|
|
789 {NULL, "rtl-all", NULL, TDF_RTL, 0, 0},
|
|
790 {NULL, "ipa-all", NULL, TDF_IPA, 0, 0},
|
|
791 };
|
|
792
|
|
793 /* Dynamically registered tree dump files and switches. */
|
|
794 static struct dump_file_info *extra_dump_files;
|
|
795 static size_t extra_dump_files_in_use;
|
|
796 static size_t extra_dump_files_alloced;
|
|
797
|
|
798 /* Define a name->number mapping for a dump flag value. */
|
|
799 struct dump_option_value_info
|
|
800 {
|
|
801 const char *const name; /* the name of the value */
|
|
802 const int value; /* the value of the name */
|
|
803 };
|
|
804
|
|
805 /* Table of dump options. This must be consistent with the TDF_* flags
|
|
806 in tree.h */
|
|
807 static const struct dump_option_value_info dump_options[] =
|
|
808 {
|
|
809 {"address", TDF_ADDRESS},
|
|
810 {"slim", TDF_SLIM},
|
|
811 {"raw", TDF_RAW},
|
|
812 {"graph", TDF_GRAPH},
|
|
813 {"details", TDF_DETAILS},
|
|
814 {"stats", TDF_STATS},
|
|
815 {"blocks", TDF_BLOCKS},
|
|
816 {"vops", TDF_VOPS},
|
|
817 {"lineno", TDF_LINENO},
|
|
818 {"uid", TDF_UID},
|
|
819 {"stmtaddr", TDF_STMTADDR},
|
|
820 {"memsyms", TDF_MEMSYMS},
|
|
821 {"verbose", TDF_VERBOSE},
|
|
822 {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
|
|
823 | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
|
|
824 | TDF_RHS_ONLY)},
|
|
825 {NULL, 0}
|
|
826 };
|
|
827
|
|
828 unsigned int
|
|
829 dump_register (const char *suffix, const char *swtch, const char *glob,
|
|
830 int flags)
|
|
831 {
|
|
832 static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
|
|
833 int num = next_dump++;
|
|
834
|
|
835 size_t count = extra_dump_files_in_use++;
|
|
836
|
|
837 if (count >= extra_dump_files_alloced)
|
|
838 {
|
|
839 if (extra_dump_files_alloced == 0)
|
|
840 extra_dump_files_alloced = 32;
|
|
841 else
|
|
842 extra_dump_files_alloced *= 2;
|
|
843 extra_dump_files = XRESIZEVEC (struct dump_file_info,
|
|
844 extra_dump_files,
|
|
845 extra_dump_files_alloced);
|
|
846 }
|
|
847
|
|
848 memset (&extra_dump_files[count], 0, sizeof (struct dump_file_info));
|
|
849 extra_dump_files[count].suffix = suffix;
|
|
850 extra_dump_files[count].swtch = swtch;
|
|
851 extra_dump_files[count].glob = glob;
|
|
852 extra_dump_files[count].flags = flags;
|
|
853 extra_dump_files[count].num = num;
|
|
854
|
|
855 return count + TDI_end;
|
|
856 }
|
|
857
|
|
858
|
|
859 /* Return the dump_file_info for the given phase. */
|
|
860
|
|
861 struct dump_file_info *
|
|
862 get_dump_file_info (enum tree_dump_index phase)
|
|
863 {
|
|
864 if (phase < TDI_end)
|
|
865 return &dump_files[phase];
|
|
866 else if (phase - TDI_end >= extra_dump_files_in_use)
|
|
867 return NULL;
|
|
868 else
|
|
869 return extra_dump_files + (phase - TDI_end);
|
|
870 }
|
|
871
|
|
872
|
|
873 /* Return the name of the dump file for the given phase.
|
|
874 If the dump is not enabled, returns NULL. */
|
|
875
|
|
876 char *
|
|
877 get_dump_file_name (enum tree_dump_index phase)
|
|
878 {
|
|
879 char dump_id[10];
|
|
880 struct dump_file_info *dfi;
|
|
881
|
|
882 if (phase == TDI_none)
|
|
883 return NULL;
|
|
884
|
|
885 dfi = get_dump_file_info (phase);
|
|
886 if (dfi->state == 0)
|
|
887 return NULL;
|
|
888
|
|
889 if (dfi->num < 0)
|
|
890 dump_id[0] = '\0';
|
|
891 else
|
|
892 {
|
|
893 char suffix;
|
|
894 if (dfi->flags & TDF_TREE)
|
|
895 suffix = 't';
|
|
896 else if (dfi->flags & TDF_IPA)
|
|
897 suffix = 'i';
|
|
898 else
|
|
899 suffix = 'r';
|
|
900
|
|
901 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
|
|
902 dump_id[0] = '\0';
|
|
903 }
|
|
904
|
|
905 return concat (dump_base_name, dump_id, dfi->suffix, NULL);
|
|
906 }
|
|
907
|
|
908 /* Begin a tree dump for PHASE. Stores any user supplied flag in
|
|
909 *FLAG_PTR and returns a stream to write to. If the dump is not
|
|
910 enabled, returns NULL.
|
|
911 Multiple calls will reopen and append to the dump file. */
|
|
912
|
|
913 FILE *
|
|
914 dump_begin (enum tree_dump_index phase, int *flag_ptr)
|
|
915 {
|
|
916 char *name;
|
|
917 struct dump_file_info *dfi;
|
|
918 FILE *stream;
|
|
919
|
|
920 if (phase == TDI_none || !dump_enabled_p (phase))
|
|
921 return NULL;
|
|
922
|
|
923 name = get_dump_file_name (phase);
|
|
924 dfi = get_dump_file_info (phase);
|
|
925 stream = fopen (name, dfi->state < 0 ? "w" : "a");
|
|
926 if (!stream)
|
|
927 error ("could not open dump file %qs: %s", name, strerror (errno));
|
|
928 else
|
|
929 dfi->state = 1;
|
|
930 free (name);
|
|
931
|
|
932 if (flag_ptr)
|
|
933 *flag_ptr = dfi->flags;
|
|
934
|
|
935 return stream;
|
|
936 }
|
|
937
|
|
938 /* Returns nonzero if tree dump PHASE is enabled. If PHASE is
|
|
939 TDI_tree_all, return nonzero if any dump is enabled. */
|
|
940
|
|
941 int
|
|
942 dump_enabled_p (enum tree_dump_index phase)
|
|
943 {
|
|
944 if (phase == TDI_tree_all)
|
|
945 {
|
|
946 size_t i;
|
|
947 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
|
|
948 if (dump_files[i].state)
|
|
949 return 1;
|
|
950 for (i = 0; i < extra_dump_files_in_use; i++)
|
|
951 if (extra_dump_files[i].state)
|
|
952 return 1;
|
|
953 return 0;
|
|
954 }
|
|
955 else
|
|
956 {
|
|
957 struct dump_file_info *dfi = get_dump_file_info (phase);
|
|
958 return dfi->state;
|
|
959 }
|
|
960 }
|
|
961
|
|
962 /* Returns nonzero if tree dump PHASE has been initialized. */
|
|
963
|
|
964 int
|
|
965 dump_initialized_p (enum tree_dump_index phase)
|
|
966 {
|
|
967 struct dump_file_info *dfi = get_dump_file_info (phase);
|
|
968 return dfi->state > 0;
|
|
969 }
|
|
970
|
|
971 /* Returns the switch name of PHASE. */
|
|
972
|
|
973 const char *
|
|
974 dump_flag_name (enum tree_dump_index phase)
|
|
975 {
|
|
976 struct dump_file_info *dfi = get_dump_file_info (phase);
|
|
977 return dfi->swtch;
|
|
978 }
|
|
979
|
|
980 /* Finish a tree dump for PHASE. STREAM is the stream created by
|
|
981 dump_begin. */
|
|
982
|
|
983 void
|
|
984 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
|
|
985 {
|
|
986 fclose (stream);
|
|
987 }
|
|
988
|
|
989 /* Enable all tree dumps. Return number of enabled tree dumps. */
|
|
990
|
|
991 static int
|
|
992 dump_enable_all (int flags)
|
|
993 {
|
|
994 int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
|
|
995 int n = 0;
|
|
996 size_t i;
|
|
997
|
|
998 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
|
|
999 if ((dump_files[i].flags & ir_dump_type))
|
|
1000 {
|
|
1001 dump_files[i].state = -1;
|
|
1002 dump_files[i].flags |= flags;
|
|
1003 n++;
|
|
1004 }
|
|
1005
|
|
1006 for (i = 0; i < extra_dump_files_in_use; i++)
|
|
1007 if ((extra_dump_files[i].flags & ir_dump_type))
|
|
1008 {
|
|
1009 extra_dump_files[i].state = -1;
|
|
1010 extra_dump_files[i].flags |= flags;
|
|
1011 n++;
|
|
1012 }
|
|
1013
|
|
1014 return n;
|
|
1015 }
|
|
1016
|
|
1017 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
|
|
1018 relevant details in the dump_files array. */
|
|
1019
|
|
1020 static int
|
|
1021 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
|
|
1022 {
|
|
1023 const char *option_value;
|
|
1024 const char *ptr;
|
|
1025 int flags;
|
|
1026
|
|
1027 if (doglob && !dfi->glob)
|
|
1028 return 0;
|
|
1029
|
|
1030 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
|
|
1031 if (!option_value)
|
|
1032 return 0;
|
|
1033
|
|
1034 if (*option_value && *option_value != '-')
|
|
1035 return 0;
|
|
1036
|
|
1037 ptr = option_value;
|
|
1038 flags = 0;
|
|
1039
|
|
1040 while (*ptr)
|
|
1041 {
|
|
1042 const struct dump_option_value_info *option_ptr;
|
|
1043 const char *end_ptr;
|
|
1044 unsigned length;
|
|
1045
|
|
1046 while (*ptr == '-')
|
|
1047 ptr++;
|
|
1048 end_ptr = strchr (ptr, '-');
|
|
1049 if (!end_ptr)
|
|
1050 end_ptr = ptr + strlen (ptr);
|
|
1051 length = end_ptr - ptr;
|
|
1052
|
|
1053 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
|
|
1054 if (strlen (option_ptr->name) == length
|
|
1055 && !memcmp (option_ptr->name, ptr, length))
|
|
1056 {
|
|
1057 flags |= option_ptr->value;
|
|
1058 goto found;
|
|
1059 }
|
|
1060 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
|
|
1061 length, ptr, dfi->swtch);
|
|
1062 found:;
|
|
1063 ptr = end_ptr;
|
|
1064 }
|
|
1065
|
|
1066 dfi->state = -1;
|
|
1067 dfi->flags |= flags;
|
|
1068
|
|
1069 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
|
|
1070 known dumps. */
|
|
1071 if (dfi->suffix == NULL)
|
|
1072 dump_enable_all (dfi->flags);
|
|
1073
|
|
1074 return 1;
|
|
1075 }
|
|
1076
|
|
1077 int
|
|
1078 dump_switch_p (const char *arg)
|
|
1079 {
|
|
1080 size_t i;
|
|
1081 int any = 0;
|
|
1082
|
|
1083 for (i = TDI_none + 1; i != TDI_end; i++)
|
|
1084 any |= dump_switch_p_1 (arg, &dump_files[i], false);
|
|
1085
|
|
1086 /* Don't glob if we got a hit already */
|
|
1087 if (!any)
|
|
1088 for (i = TDI_none + 1; i != TDI_end; i++)
|
|
1089 any |= dump_switch_p_1 (arg, &dump_files[i], true);
|
|
1090
|
|
1091 for (i = 0; i < extra_dump_files_in_use; i++)
|
|
1092 any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
|
|
1093
|
|
1094 if (!any)
|
|
1095 for (i = 0; i < extra_dump_files_in_use; i++)
|
|
1096 any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
|
|
1097
|
|
1098
|
|
1099 return any;
|
|
1100 }
|
|
1101
|
|
1102 /* Dump FUNCTION_DECL FN as tree dump PHASE. */
|
|
1103
|
|
1104 void
|
|
1105 dump_function (enum tree_dump_index phase, tree fn)
|
|
1106 {
|
|
1107 FILE *stream;
|
|
1108 int flags;
|
|
1109
|
|
1110 stream = dump_begin (phase, &flags);
|
|
1111 if (stream)
|
|
1112 {
|
|
1113 dump_function_to_file (fn, stream, flags);
|
|
1114 dump_end (phase, stream);
|
|
1115 }
|
|
1116 }
|
|
1117
|
|
1118 bool
|
|
1119 enable_rtl_dump_file (void)
|
|
1120 {
|
|
1121 return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS) > 0;
|
|
1122 }
|
|
1123
|
|
1124
|