Mercurial > hg > CbC > CbC_gcc
comparison gcc/tree-dump.c @ 0:a06113de4d67
first commit
author | kent <kent@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 17 Jul 2009 14:47:48 +0900 |
parents | |
children | 77e2b8dfacca |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:a06113de4d67 |
---|---|
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 |