| /* Prints out tree in human readable form - GCC |
| Copyright (C) 1990-2021 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "tm.h" |
| #include "tree.h" |
| #include "cgraph.h" |
| #include "diagnostic.h" |
| #include "varasm.h" |
| #include "print-rtl.h" |
| #include "stor-layout.h" |
| #include "langhooks.h" |
| #include "tree-iterator.h" |
| #include "gimple-pretty-print.h" /* FIXME */ |
| #include "tree-cfg.h" |
| #include "dumpfile.h" |
| #include "print-tree.h" |
| |
| /* Define the hash table of nodes already seen. |
| Such nodes are not repeated; brief cross-references are used. */ |
| |
| #define HASH_SIZE 37 |
| |
| static hash_set<tree> *table = NULL; |
| |
| /* Print PREFIX and ADDR to FILE. */ |
| void |
| dump_addr (FILE *file, const char *prefix, const void *addr) |
| { |
| if (flag_dump_noaddr || flag_dump_unnumbered) |
| fprintf (file, "%s#", prefix); |
| else |
| fprintf (file, "%s" HOST_PTR_PRINTF, prefix, addr); |
| } |
| |
| /* Print to FILE a NODE representing a REAL_CST constant, including |
| Infinity and NaN. Be verbose when BFRIEF is false. */ |
| |
| static void |
| print_real_cst (FILE *file, const_tree node, bool brief) |
| { |
| if (TREE_OVERFLOW (node)) |
| fprintf (file, " overflow"); |
| |
| REAL_VALUE_TYPE d = TREE_REAL_CST (node); |
| if (REAL_VALUE_ISINF (d)) |
| fprintf (file, REAL_VALUE_NEGATIVE (d) ? " -Inf" : " Inf"); |
| else if (REAL_VALUE_ISNAN (d)) |
| { |
| /* Print a NaN in the format [-][Q]NaN[(significand[exponent])] |
| where significand is a hexadecimal string that starts with |
| the 0x prefix followed by 0 if the number is not canonical |
| and a non-zero digit if it is, and exponent is decimal. */ |
| unsigned start = 0; |
| const char *psig = (const char *) d.sig; |
| for (unsigned i = 0; i != sizeof d.sig; ++i) |
| if (psig[i]) |
| { |
| start = i; |
| break; |
| } |
| |
| fprintf (file, " %s%sNaN", d.sign ? "-" : "", |
| d.signalling ? "S" : "Q"); |
| |
| if (brief) |
| return; |
| |
| if (start) |
| fprintf (file, "(0x%s", d.canonical ? "" : "0"); |
| else if (d.uexp) |
| fprintf (file, "(%s", d.canonical ? "" : "0"); |
| else if (!d.canonical) |
| { |
| fprintf (file, "(0)"); |
| return; |
| } |
| |
| if (psig[start]) |
| { |
| for (unsigned i = start; i != sizeof d.sig; ++i) |
| if (i == start) |
| fprintf (file, "%x", psig[i]); |
| else |
| fprintf (file, "%02x", psig[i]); |
| } |
| |
| if (d.uexp) |
| fprintf (file, "%se%u)", psig[start] ? "," : "", d.uexp); |
| else if (psig[start]) |
| fputc (')', file); |
| } |
| else |
| { |
| char string[64]; |
| real_to_decimal (string, &d, sizeof (string), 0, 1); |
| fprintf (file, " %s", string); |
| } |
| } |
| |
| /* Print a node in brief fashion, with just the code, address and name. */ |
| |
| void |
| print_node_brief (FILE *file, const char *prefix, const_tree node, int indent) |
| { |
| enum tree_code_class tclass; |
| |
| if (node == 0) |
| return; |
| |
| tclass = TREE_CODE_CLASS (TREE_CODE (node)); |
| |
| /* Always print the slot this node is in, and its code, address and |
| name if any. */ |
| if (indent > 0) |
| fprintf (file, " "); |
| fprintf (file, "%s <%s", prefix, get_tree_code_name (TREE_CODE (node))); |
| dump_addr (file, " ", node); |
| |
| if (tclass == tcc_declaration) |
| { |
| if (DECL_NAME (node)) |
| fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); |
| else if (TREE_CODE (node) == LABEL_DECL |
| && LABEL_DECL_UID (node) != -1) |
| { |
| if (dump_flags & TDF_NOUID) |
| fprintf (file, " L.xxxx"); |
| else |
| fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); |
| } |
| else |
| { |
| if (dump_flags & TDF_NOUID) |
| fprintf (file, " %c.xxxx", |
| TREE_CODE (node) == CONST_DECL ? 'C' : 'D'); |
| else |
| fprintf (file, " %c.%u", |
| TREE_CODE (node) == CONST_DECL ? 'C' : 'D', |
| DECL_UID (node)); |
| } |
| } |
| else if (tclass == tcc_type) |
| { |
| if (TYPE_NAME (node)) |
| { |
| if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) |
| fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); |
| else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL |
| && DECL_NAME (TYPE_NAME (node))) |
| fprintf (file, " %s", |
| IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); |
| } |
| if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) |
| fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); |
| } |
| if (TREE_CODE (node) == IDENTIFIER_NODE) |
| fprintf (file, " %s", IDENTIFIER_POINTER (node)); |
| |
| /* We might as well always print the value of an integer or real. */ |
| if (TREE_CODE (node) == INTEGER_CST) |
| { |
| if (TREE_OVERFLOW (node)) |
| fprintf (file, " overflow"); |
| |
| fprintf (file, " "); |
| print_dec (wi::to_wide (node), file, TYPE_SIGN (TREE_TYPE (node))); |
| } |
| if (TREE_CODE (node) == REAL_CST) |
| print_real_cst (file, node, true); |
| if (TREE_CODE (node) == FIXED_CST) |
| { |
| FIXED_VALUE_TYPE f; |
| char string[60]; |
| |
| if (TREE_OVERFLOW (node)) |
| fprintf (file, " overflow"); |
| |
| f = TREE_FIXED_CST (node); |
| fixed_to_decimal (string, &f, sizeof (string)); |
| fprintf (file, " %s", string); |
| } |
| |
| fprintf (file, ">"); |
| } |
| |
| void |
| indent_to (FILE *file, int column) |
| { |
| int i; |
| |
| /* Since this is the long way, indent to desired column. */ |
| if (column > 0) |
| fprintf (file, "\n"); |
| for (i = 0; i < column; i++) |
| fprintf (file, " "); |
| } |
| |
| /* Print the node NODE in full on file FILE, preceded by PREFIX, |
| starting in column INDENT. */ |
| |
| void |
| print_node (FILE *file, const char *prefix, tree node, int indent, |
| bool brief_for_visited) |
| { |
| machine_mode mode; |
| enum tree_code_class tclass; |
| int len; |
| int i; |
| expanded_location xloc; |
| enum tree_code code; |
| |
| if (node == 0) |
| return; |
| |
| code = TREE_CODE (node); |
| |
| /* It is unsafe to look at any other fields of a node with ERROR_MARK or |
| invalid code. */ |
| if (code == ERROR_MARK || code >= MAX_TREE_CODES) |
| { |
| print_node_brief (file, prefix, node, indent); |
| return; |
| } |
| |
| tclass = TREE_CODE_CLASS (code); |
| |
| /* Don't get too deep in nesting. If the user wants to see deeper, |
| it is easy to use the address of a lowest-level node |
| as an argument in another call to debug_tree. */ |
| |
| if (indent > 24) |
| { |
| print_node_brief (file, prefix, node, indent); |
| return; |
| } |
| |
| if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) |
| { |
| print_node_brief (file, prefix, node, indent); |
| return; |
| } |
| |
| /* Allow this function to be called if the table is not there. */ |
| if (table) |
| { |
| /* If node is in the table, just mention its address. */ |
| if (table->contains (node) && brief_for_visited) |
| { |
| print_node_brief (file, prefix, node, indent); |
| return; |
| } |
| |
| table->add (node); |
| } |
| |
| /* Indent to the specified column, since this is the long form. */ |
| indent_to (file, indent); |
| |
| /* Print the slot this node is in, and its code, and address. */ |
| fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); |
| dump_addr (file, " ", node); |
| |
| /* Print the name, if any. */ |
| if (tclass == tcc_declaration) |
| { |
| if (DECL_NAME (node)) |
| fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); |
| else if (code == LABEL_DECL |
| && LABEL_DECL_UID (node) != -1) |
| { |
| if (dump_flags & TDF_NOUID) |
| fprintf (file, " L.xxxx"); |
| else |
| fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); |
| } |
| else |
| { |
| if (dump_flags & TDF_NOUID) |
| fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); |
| else |
| fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', |
| DECL_UID (node)); |
| } |
| } |
| else if (tclass == tcc_type) |
| { |
| if (TYPE_NAME (node)) |
| { |
| if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) |
| fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); |
| else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL |
| && DECL_NAME (TYPE_NAME (node))) |
| fprintf (file, " %s", |
| IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); |
| } |
| } |
| if (code == IDENTIFIER_NODE) |
| fprintf (file, " %s", IDENTIFIER_POINTER (node)); |
| |
| if (code == INTEGER_CST) |
| { |
| if (indent <= 4) |
| print_node_brief (file, "type", TREE_TYPE (node), indent + 4); |
| } |
| else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) |
| { |
| print_node (file, "type", TREE_TYPE (node), indent + 4); |
| if (TREE_TYPE (node)) |
| indent_to (file, indent + 3); |
| } |
| |
| if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) |
| fputs (" side-effects", file); |
| |
| if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) |
| fputs (" readonly", file); |
| if (TYPE_P (node) && TYPE_ATOMIC (node)) |
| fputs (" atomic", file); |
| if (!TYPE_P (node) && TREE_CONSTANT (node)) |
| fputs (" constant", file); |
| else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) |
| fputs (" sizes-gimplified", file); |
| |
| if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) |
| fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); |
| |
| if (TREE_ADDRESSABLE (node)) |
| fputs (" addressable", file); |
| if (TREE_THIS_VOLATILE (node)) |
| fputs (" volatile", file); |
| if (TREE_ASM_WRITTEN (node)) |
| fputs (" asm_written", file); |
| if (TREE_USED (node)) |
| fputs (" used", file); |
| if (TREE_NOTHROW (node)) |
| fputs (" nothrow", file); |
| if (TREE_PUBLIC (node)) |
| fputs (" public", file); |
| if (TREE_PRIVATE (node)) |
| fputs (" private", file); |
| if (TREE_PROTECTED (node)) |
| fputs (" protected", file); |
| if (TREE_STATIC (node)) |
| fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); |
| if (TREE_DEPRECATED (node)) |
| fputs (" deprecated", file); |
| if (TREE_UNAVAILABLE (node)) |
| fputs (" unavailable", file); |
| if (TREE_VISITED (node)) |
| fputs (" visited", file); |
| |
| if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) |
| { |
| if (TREE_LANG_FLAG_0 (node)) |
| fputs (" tree_0", file); |
| if (TREE_LANG_FLAG_1 (node)) |
| fputs (" tree_1", file); |
| if (TREE_LANG_FLAG_2 (node)) |
| fputs (" tree_2", file); |
| if (TREE_LANG_FLAG_3 (node)) |
| fputs (" tree_3", file); |
| if (TREE_LANG_FLAG_4 (node)) |
| fputs (" tree_4", file); |
| if (TREE_LANG_FLAG_5 (node)) |
| fputs (" tree_5", file); |
| if (TREE_LANG_FLAG_6 (node)) |
| fputs (" tree_6", file); |
| } |
| |
| /* DECL_ nodes have additional attributes. */ |
| |
| switch (TREE_CODE_CLASS (code)) |
| { |
| case tcc_declaration: |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) |
| { |
| if (DECL_UNSIGNED (node)) |
| fputs (" unsigned", file); |
| if (DECL_IGNORED_P (node)) |
| fputs (" ignored", file); |
| if (DECL_ABSTRACT_P (node)) |
| fputs (" abstract", file); |
| if (DECL_EXTERNAL (node)) |
| fputs (" external", file); |
| if (DECL_NONLOCAL (node)) |
| fputs (" nonlocal", file); |
| } |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) |
| { |
| if (DECL_WEAK (node)) |
| fputs (" weak", file); |
| if (DECL_IN_SYSTEM_HEADER (node)) |
| fputs (" in_system_header", file); |
| } |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) |
| && code != LABEL_DECL |
| && code != FUNCTION_DECL |
| && DECL_REGISTER (node)) |
| fputs (" regdecl", file); |
| |
| if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) |
| fputs (" suppress-debug", file); |
| |
| if (code == FUNCTION_DECL |
| && DECL_FUNCTION_SPECIFIC_TARGET (node)) |
| fputs (" function-specific-target", file); |
| if (code == FUNCTION_DECL |
| && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) |
| fputs (" function-specific-opt", file); |
| if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) |
| fputs (" autoinline", file); |
| if (code == FUNCTION_DECL && DECL_UNINLINABLE (node)) |
| fputs (" uninlinable", file); |
| if (code == FUNCTION_DECL && fndecl_built_in_p (node)) |
| fputs (" built-in", file); |
| if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) |
| fputs (" static-chain", file); |
| if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) |
| fputs (" tm-clone", file); |
| |
| if (code == FIELD_DECL && DECL_PACKED (node)) |
| fputs (" packed", file); |
| if (code == FIELD_DECL && DECL_BIT_FIELD (node)) |
| fputs (" bit-field", file); |
| if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) |
| fputs (" nonaddressable", file); |
| |
| if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) |
| fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); |
| |
| if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) |
| fputs (" in-text-section", file); |
| if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) |
| fputs (" in-constant-pool", file); |
| if (code == VAR_DECL && DECL_COMMON (node)) |
| fputs (" common", file); |
| if ((code == VAR_DECL || code == PARM_DECL) && DECL_READ_P (node)) |
| fputs (" read", file); |
| if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) |
| { |
| fputs (" ", file); |
| fputs (tls_model_names[DECL_TLS_MODEL (node)], file); |
| } |
| |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) |
| { |
| if (DECL_VIRTUAL_P (node)) |
| fputs (" virtual", file); |
| if (DECL_PRESERVE_P (node)) |
| fputs (" preserve", file); |
| if (DECL_LANG_FLAG_0 (node)) |
| fputs (" decl_0", file); |
| if (DECL_LANG_FLAG_1 (node)) |
| fputs (" decl_1", file); |
| if (DECL_LANG_FLAG_2 (node)) |
| fputs (" decl_2", file); |
| if (DECL_LANG_FLAG_3 (node)) |
| fputs (" decl_3", file); |
| if (DECL_LANG_FLAG_4 (node)) |
| fputs (" decl_4", file); |
| if (DECL_LANG_FLAG_5 (node)) |
| fputs (" decl_5", file); |
| if (DECL_LANG_FLAG_6 (node)) |
| fputs (" decl_6", file); |
| if (DECL_LANG_FLAG_7 (node)) |
| fputs (" decl_7", file); |
| |
| mode = DECL_MODE (node); |
| fprintf (file, " %s", GET_MODE_NAME (mode)); |
| } |
| |
| if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) |
| && DECL_BY_REFERENCE (node)) |
| fputs (" passed-by-reference", file); |
| |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) |
| fputs (" defer-output", file); |
| |
| |
| xloc = expand_location (DECL_SOURCE_LOCATION (node)); |
| fprintf (file, " %s:%d:%d", xloc.file, xloc.line, |
| xloc.column); |
| |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) |
| { |
| print_node (file, "size", DECL_SIZE (node), indent + 4); |
| print_node (file, "unit-size", DECL_SIZE_UNIT (node), indent + 4); |
| |
| if (code != FUNCTION_DECL || fndecl_built_in_p (node)) |
| indent_to (file, indent + 3); |
| |
| if (DECL_USER_ALIGN (node)) |
| fprintf (file, " user"); |
| |
| fprintf (file, " align:%d warn_if_not_align:%d", |
| DECL_ALIGN (node), DECL_WARN_IF_NOT_ALIGN (node)); |
| if (code == FIELD_DECL) |
| fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, |
| DECL_OFFSET_ALIGN (node)); |
| |
| if (code == FUNCTION_DECL && fndecl_built_in_p (node)) |
| { |
| if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) |
| fprintf (file, " built-in: BUILT_IN_MD:%d", |
| DECL_MD_FUNCTION_CODE (node)); |
| else if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_FRONTEND) |
| fprintf (file, " built-in: BUILT_IN_FRONTEND:%d", |
| DECL_FE_FUNCTION_CODE (node)); |
| else |
| fprintf (file, " built-in: %s:%s", |
| built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], |
| built_in_names[(int) DECL_FUNCTION_CODE (node)]); |
| } |
| } |
| if (code == FIELD_DECL) |
| { |
| print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); |
| print_node (file, "bit-offset", DECL_FIELD_BIT_OFFSET (node), |
| indent + 4); |
| if (DECL_BIT_FIELD_TYPE (node)) |
| print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), |
| indent + 4); |
| } |
| |
| print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); |
| |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) |
| { |
| print_node (file, "attributes", |
| DECL_ATTRIBUTES (node), indent + 4); |
| if (code != PARM_DECL) |
| print_node_brief (file, "initial", DECL_INITIAL (node), |
| indent + 4); |
| } |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) |
| { |
| print_node_brief (file, "abstract_origin", |
| DECL_ABSTRACT_ORIGIN (node), indent + 4); |
| } |
| if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) |
| { |
| print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); |
| } |
| |
| lang_hooks.print_decl (file, node, indent); |
| |
| if (DECL_RTL_SET_P (node)) |
| { |
| indent_to (file, indent + 4); |
| print_rtl (file, DECL_RTL (node)); |
| } |
| |
| if (code == PARM_DECL) |
| { |
| print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); |
| |
| if (DECL_INCOMING_RTL (node) != 0) |
| { |
| indent_to (file, indent + 4); |
| fprintf (file, "incoming-rtl "); |
| print_rtl (file, DECL_INCOMING_RTL (node)); |
| } |
| } |
| else if (code == FUNCTION_DECL |
| && DECL_STRUCT_FUNCTION (node) != 0) |
| { |
| print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); |
| indent_to (file, indent + 4); |
| dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); |
| } |
| |
| if ((code == VAR_DECL || code == PARM_DECL) |
| && DECL_HAS_VALUE_EXPR_P (node)) |
| print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); |
| |
| /* Print the decl chain only if decl is at second level. */ |
| if (indent == 4) |
| print_node (file, "chain", TREE_CHAIN (node), indent + 4); |
| else |
| print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); |
| break; |
| |
| case tcc_type: |
| if (TYPE_UNSIGNED (node)) |
| fputs (" unsigned", file); |
| |
| if (TYPE_NO_FORCE_BLK (node)) |
| fputs (" no-force-blk", file); |
| |
| if (code == ARRAY_TYPE && TYPE_STRING_FLAG (node)) |
| fputs (" string-flag", file); |
| |
| if (TYPE_NEEDS_CONSTRUCTING (node)) |
| fputs (" needs-constructing", file); |
| |
| if ((code == RECORD_TYPE |
| || code == UNION_TYPE |
| || code == QUAL_UNION_TYPE |
| || code == ARRAY_TYPE) |
| && TYPE_REVERSE_STORAGE_ORDER (node)) |
| fputs (" reverse-storage-order", file); |
| |
| if ((code == RECORD_TYPE |
| || code == UNION_TYPE) |
| && TYPE_CXX_ODR_P (node)) |
| fputs (" cxx-odr-p", file); |
| |
| /* The transparent-union flag is used for different things in |
| different nodes. */ |
| if ((code == UNION_TYPE || code == RECORD_TYPE) |
| && TYPE_TRANSPARENT_AGGR (node)) |
| fputs (" transparent-aggr", file); |
| else if (code == ARRAY_TYPE |
| && TYPE_NONALIASED_COMPONENT (node)) |
| fputs (" nonaliased-component", file); |
| |
| if (TYPE_PACKED (node)) |
| fputs (" packed", file); |
| |
| if (TYPE_RESTRICT (node)) |
| fputs (" restrict", file); |
| |
| if (TYPE_LANG_FLAG_0 (node)) |
| fputs (" type_0", file); |
| if (TYPE_LANG_FLAG_1 (node)) |
| fputs (" type_1", file); |
| if (TYPE_LANG_FLAG_2 (node)) |
| fputs (" type_2", file); |
| if (TYPE_LANG_FLAG_3 (node)) |
| fputs (" type_3", file); |
| if (TYPE_LANG_FLAG_4 (node)) |
| fputs (" type_4", file); |
| if (TYPE_LANG_FLAG_5 (node)) |
| fputs (" type_5", file); |
| if (TYPE_LANG_FLAG_6 (node)) |
| fputs (" type_6", file); |
| if (TYPE_LANG_FLAG_7 (node)) |
| fputs (" type_7", file); |
| |
| mode = TYPE_MODE (node); |
| fprintf (file, " %s", GET_MODE_NAME (mode)); |
| |
| print_node (file, "size", TYPE_SIZE (node), indent + 4); |
| print_node (file, "unit-size", TYPE_SIZE_UNIT (node), indent + 4); |
| indent_to (file, indent + 3); |
| |
| if (TYPE_USER_ALIGN (node)) |
| fprintf (file, " user"); |
| |
| fprintf (file, " align:%d warn_if_not_align:%d symtab:%d alias-set " |
| HOST_WIDE_INT_PRINT_DEC, |
| TYPE_ALIGN (node), TYPE_WARN_IF_NOT_ALIGN (node), |
| TYPE_SYMTAB_ADDRESS (node), |
| (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); |
| |
| if (TYPE_STRUCTURAL_EQUALITY_P (node)) |
| fprintf (file, " structural-equality"); |
| else |
| dump_addr (file, " canonical-type ", TYPE_CANONICAL (node)); |
| |
| print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); |
| |
| if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE |
| || code == FIXED_POINT_TYPE) |
| { |
| fprintf (file, " precision:%d", TYPE_PRECISION (node)); |
| print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); |
| print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); |
| } |
| |
| if (code == ENUMERAL_TYPE) |
| print_node (file, "values", TYPE_VALUES (node), indent + 4); |
| else if (code == ARRAY_TYPE) |
| print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); |
| else if (code == VECTOR_TYPE) |
| { |
| fprintf (file, " nunits:"); |
| print_dec (TYPE_VECTOR_SUBPARTS (node), file); |
| } |
| else if (code == RECORD_TYPE |
| || code == UNION_TYPE |
| || code == QUAL_UNION_TYPE) |
| print_node (file, "fields", TYPE_FIELDS (node), indent + 4); |
| else if (code == FUNCTION_TYPE |
| || code == METHOD_TYPE) |
| { |
| if (TYPE_METHOD_BASETYPE (node)) |
| print_node_brief (file, "method basetype", |
| TYPE_METHOD_BASETYPE (node), indent + 4); |
| print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); |
| } |
| else if (code == OFFSET_TYPE) |
| print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), |
| indent + 4); |
| |
| if (TYPE_CONTEXT (node)) |
| print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); |
| |
| lang_hooks.print_type (file, node, indent); |
| |
| if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) |
| indent_to (file, indent + 3); |
| |
| print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), |
| indent + 4); |
| print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), |
| indent + 4); |
| print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); |
| break; |
| |
| case tcc_expression: |
| case tcc_comparison: |
| case tcc_unary: |
| case tcc_binary: |
| case tcc_reference: |
| case tcc_statement: |
| case tcc_vl_exp: |
| if (code == BIND_EXPR) |
| { |
| print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); |
| print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); |
| print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); |
| break; |
| } |
| if (code == CALL_EXPR) |
| { |
| print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); |
| print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), |
| indent + 4); |
| |
| call_expr_arg_iterator iter; |
| init_call_expr_arg_iterator (node, &iter); |
| while (more_call_expr_args_p (&iter)) |
| { |
| /* Buffer big enough to format a 32-bit UINT_MAX into, plus |
| the text. */ |
| char temp[15]; |
| sprintf (temp, "arg:%u", iter.i); |
| tree arg = next_call_expr_arg (&iter); |
| if (arg) |
| print_node (file, temp, arg, indent + 4); |
| else |
| { |
| indent_to (file, indent + 4); |
| fprintf (file, "%s NULL", temp); |
| } |
| } |
| } |
| else |
| { |
| len = TREE_OPERAND_LENGTH (node); |
| |
| for (i = 0; i < len; i++) |
| { |
| /* Buffer big enough to format a 32-bit UINT_MAX into, plus |
| the text. */ |
| char temp[15]; |
| |
| sprintf (temp, "arg:%d", i); |
| print_node (file, temp, TREE_OPERAND (node, i), indent + 4); |
| } |
| } |
| if (CODE_CONTAINS_STRUCT (code, TS_COMMON)) |
| print_node (file, "chain", TREE_CHAIN (node), indent + 4); |
| break; |
| |
| case tcc_constant: |
| case tcc_exceptional: |
| switch (code) |
| { |
| case INTEGER_CST: |
| if (TREE_OVERFLOW (node)) |
| fprintf (file, " overflow"); |
| |
| fprintf (file, " "); |
| print_dec (wi::to_wide (node), file, TYPE_SIGN (TREE_TYPE (node))); |
| break; |
| |
| case REAL_CST: |
| print_real_cst (file, node, false); |
| break; |
| |
| case FIXED_CST: |
| { |
| FIXED_VALUE_TYPE f; |
| char string[64]; |
| |
| if (TREE_OVERFLOW (node)) |
| fprintf (file, " overflow"); |
| |
| f = TREE_FIXED_CST (node); |
| fixed_to_decimal (string, &f, sizeof (string)); |
| fprintf (file, " %s", string); |
| } |
| break; |
| |
| case VECTOR_CST: |
| { |
| /* Big enough for UINT_MAX plus the string below. */ |
| char buf[32]; |
| |
| fprintf (file, " npatterns:%u nelts-per-pattern:%u", |
| VECTOR_CST_NPATTERNS (node), |
| VECTOR_CST_NELTS_PER_PATTERN (node)); |
| unsigned int count = vector_cst_encoded_nelts (node); |
| for (unsigned int i = 0; i < count; ++i) |
| { |
| sprintf (buf, "elt:%u: ", i); |
| print_node (file, buf, VECTOR_CST_ENCODED_ELT (node, i), |
| indent + 4); |
| } |
| } |
| break; |
| |
| case COMPLEX_CST: |
| print_node (file, "real", TREE_REALPART (node), indent + 4); |
| print_node (file, "imag", TREE_IMAGPART (node), indent + 4); |
| break; |
| |
| case STRING_CST: |
| { |
| const char *p = TREE_STRING_POINTER (node); |
| int i = TREE_STRING_LENGTH (node); |
| fputs (" \"", file); |
| while (--i >= 0) |
| { |
| char ch = *p++; |
| if (ch >= ' ' && ch < 127) |
| putc (ch, file); |
| else |
| fprintf (file, "\\%03o", ch & 0xFF); |
| } |
| fputc ('\"', file); |
| } |
| break; |
| |
| case POLY_INT_CST: |
| { |
| char buf[10]; |
| for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i) |
| { |
| snprintf (buf, sizeof (buf), "elt%u:", i); |
| print_node (file, buf, POLY_INT_CST_COEFF (node, i), |
| indent + 4); |
| } |
| } |
| break; |
| |
| case IDENTIFIER_NODE: |
| lang_hooks.print_identifier (file, node, indent); |
| break; |
| |
| case TREE_LIST: |
| print_node (file, "purpose", TREE_PURPOSE (node), indent + 4); |
| print_node (file, "value", TREE_VALUE (node), indent + 4); |
| print_node (file, "chain", TREE_CHAIN (node), indent + 4); |
| break; |
| |
| case TREE_VEC: |
| len = TREE_VEC_LENGTH (node); |
| fprintf (file, " length:%d", len); |
| for (i = 0; i < len; i++) |
| if (TREE_VEC_ELT (node, i)) |
| { |
| /* Buffer big enough to format a 32-bit UINT_MAX into, plus |
| the text. */ |
| char temp[15]; |
| sprintf (temp, "elt:%d", i); |
| print_node (file, temp, TREE_VEC_ELT (node, i), indent + 4); |
| } |
| break; |
| |
| case CONSTRUCTOR: |
| { |
| unsigned HOST_WIDE_INT cnt; |
| tree index, value; |
| len = CONSTRUCTOR_NELTS (node); |
| fprintf (file, " length:%d", len); |
| FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (node), |
| cnt, index, value) |
| { |
| print_node (file, "idx", index, indent + 4, false); |
| print_node (file, "val", value, indent + 4, false); |
| } |
| } |
| break; |
| |
| case STATEMENT_LIST: |
| dump_addr (file, " head ", node->stmt_list.head); |
| dump_addr (file, " tail ", node->stmt_list.tail); |
| fprintf (file, " stmts"); |
| { |
| tree_stmt_iterator i; |
| for (i = tsi_start (node); !tsi_end_p (i); tsi_next (&i)) |
| { |
| /* Not printing the addresses of the (not-a-tree) |
| 'struct tree_stmt_list_node's. */ |
| dump_addr (file, " ", tsi_stmt (i)); |
| } |
| fprintf (file, "\n"); |
| for (i = tsi_start (node); !tsi_end_p (i); tsi_next (&i)) |
| { |
| /* Not printing the addresses of the (not-a-tree) |
| 'struct tree_stmt_list_node's. */ |
| print_node (file, "stmt", tsi_stmt (i), indent + 4); |
| } |
| } |
| break; |
| |
| case BLOCK: |
| print_node (file, "vars", BLOCK_VARS (node), indent + 4); |
| print_node (file, "supercontext", BLOCK_SUPERCONTEXT (node), |
| indent + 4); |
| print_node (file, "subblocks", BLOCK_SUBBLOCKS (node), indent + 4); |
| print_node (file, "chain", BLOCK_CHAIN (node), indent + 4); |
| print_node (file, "abstract_origin", |
| BLOCK_ABSTRACT_ORIGIN (node), indent + 4); |
| break; |
| |
| case SSA_NAME: |
| print_node_brief (file, "var", SSA_NAME_VAR (node), indent + 4); |
| indent_to (file, indent + 4); |
| fprintf (file, "def_stmt "); |
| { |
| pretty_printer buffer; |
| buffer.buffer->stream = file; |
| pp_gimple_stmt_1 (&buffer, SSA_NAME_DEF_STMT (node), indent + 4, |
| TDF_NONE); |
| pp_flush (&buffer); |
| } |
| |
| indent_to (file, indent + 4); |
| fprintf (file, "version:%u", SSA_NAME_VERSION (node)); |
| if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (node)) |
| fprintf (file, " in-abnormal-phi"); |
| if (SSA_NAME_IN_FREE_LIST (node)) |
| fprintf (file, " in-free-list"); |
| |
| if (SSA_NAME_PTR_INFO (node)) |
| { |
| indent_to (file, indent + 3); |
| if (SSA_NAME_PTR_INFO (node)) |
| dump_addr (file, " ptr-info ", SSA_NAME_PTR_INFO (node)); |
| } |
| break; |
| |
| case OMP_CLAUSE: |
| { |
| int i; |
| fprintf (file, " %s", |
| omp_clause_code_name[OMP_CLAUSE_CODE (node)]); |
| for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (node)]; i++) |
| { |
| indent_to (file, indent + 4); |
| fprintf (file, "op-%d:", i); |
| print_node_brief (file, "", OMP_CLAUSE_OPERAND (node, i), 0); |
| } |
| } |
| break; |
| |
| case OPTIMIZATION_NODE: |
| cl_optimization_print (file, indent + 4, TREE_OPTIMIZATION (node)); |
| break; |
| |
| case TARGET_OPTION_NODE: |
| cl_target_option_print (file, indent + 4, TREE_TARGET_OPTION (node)); |
| break; |
| case IMPORTED_DECL: |
| fprintf (file, " imported-declaration"); |
| print_node_brief (file, "associated-declaration", |
| IMPORTED_DECL_ASSOCIATED_DECL (node), |
| indent + 4); |
| break; |
| |
| case TREE_BINFO: |
| fprintf (file, " bases:%d", |
| vec_safe_length (BINFO_BASE_BINFOS (node))); |
| print_node_brief (file, "offset", BINFO_OFFSET (node), indent + 4); |
| print_node_brief (file, "virtuals", BINFO_VIRTUALS (node), |
| indent + 4); |
| print_node_brief (file, "inheritance-chain", |
| BINFO_INHERITANCE_CHAIN (node), |
| indent + 4); |
| break; |
| |
| default: |
| if (EXCEPTIONAL_CLASS_P (node)) |
| lang_hooks.print_xnode (file, node, indent); |
| break; |
| } |
| |
| break; |
| } |
| |
| if (EXPR_HAS_LOCATION (node)) |
| { |
| expanded_location xloc = expand_location (EXPR_LOCATION (node)); |
| indent_to (file, indent+4); |
| fprintf (file, "%s:%d:%d", xloc.file, xloc.line, xloc.column); |
| |
| /* Print the range, if any */ |
| source_range r = EXPR_LOCATION_RANGE (node); |
| if (r.m_start) |
| { |
| xloc = expand_location (r.m_start); |
| fprintf (file, " start: %s:%d:%d", xloc.file, xloc.line, xloc.column); |
| } |
| else |
| { |
| fprintf (file, " start: unknown"); |
| } |
| if (r.m_finish) |
| { |
| xloc = expand_location (r.m_finish); |
| fprintf (file, " finish: %s:%d:%d", xloc.file, xloc.line, xloc.column); |
| } |
| else |
| { |
| fprintf (file, " finish: unknown"); |
| } |
| } |
| |
| fprintf (file, ">"); |
| } |
| |
| /* Print the identifier for DECL according to FLAGS. */ |
| |
| void |
| print_decl_identifier (FILE *file, tree decl, int flags) |
| { |
| bool needs_colon = false; |
| const char *name; |
| char c; |
| |
| if (flags & PRINT_DECL_ORIGIN) |
| { |
| if (DECL_IS_UNDECLARED_BUILTIN (decl)) |
| fputs ("<built-in>", file); |
| else |
| { |
| expanded_location loc |
| = expand_location (DECL_SOURCE_LOCATION (decl)); |
| fprintf (file, "%s:%d:%d", loc.file, loc.line, loc.column); |
| } |
| needs_colon = true; |
| } |
| |
| if (flags & PRINT_DECL_UNIQUE_NAME) |
| { |
| name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); |
| if (!TREE_PUBLIC (decl) |
| || (DECL_WEAK (decl) && !DECL_EXTERNAL (decl))) |
| /* The symbol has internal or weak linkage so its assembler name |
| is not necessarily unique among the compilation units of the |
| program. We therefore have to further mangle it. But we can't |
| simply use DECL_SOURCE_FILE because it contains the name of the |
| file the symbol originates from so, e.g. for function templates |
| in C++ where the templates are defined in a header file, we can |
| have symbols with the same assembler name and DECL_SOURCE_FILE. |
| That's why we use the name of the top-level source file of the |
| compilation unit. ??? Unnecessary for Ada. */ |
| name = ACONCAT ((main_input_filename, ":", name, NULL)); |
| } |
| else if (flags & PRINT_DECL_NAME) |
| { |
| /* We don't want to print the full qualified name because it can be long, |
| so we strip the scope prefix, but we may need to deal with the suffix |
| created by the compiler. */ |
| const char *suffix = strchr (IDENTIFIER_POINTER (DECL_NAME (decl)), '.'); |
| name = lang_hooks.decl_printable_name (decl, 2); |
| if (suffix) |
| { |
| const char *dot = strchr (name, '.'); |
| while (dot && strcasecmp (dot, suffix) != 0) |
| { |
| name = dot + 1; |
| dot = strchr (name, '.'); |
| } |
| } |
| else |
| { |
| const char *dot = strrchr (name, '.'); |
| if (dot) |
| name = dot + 1; |
| } |
| } |
| else |
| return; |
| |
| if (needs_colon) |
| fputc (':', file); |
| |
| while ((c = *name++) != '\0') |
| { |
| /* Strip double-quotes because of VCG. */ |
| if (c == '"') |
| continue; |
| fputc (c, file); |
| } |
| } |
| |
| |
| /* Print the node NODE on standard error, for debugging. |
| Most nodes referred to by this one are printed recursively |
| down to a depth of six. */ |
| |
| DEBUG_FUNCTION void |
| debug_tree (tree node) |
| { |
| table = new hash_set<tree> (HASH_SIZE); |
| print_node (stderr, "", node, 0); |
| delete table; |
| table = NULL; |
| putc ('\n', stderr); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_raw (const tree_node &ref) |
| { |
| debug_tree (const_cast <tree> (&ref)); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_raw (const tree_node *ptr) |
| { |
| if (ptr) |
| debug_raw (*ptr); |
| else |
| fprintf (stderr, "<nil>\n"); |
| } |
| |
| static void |
| dump_tree_via_hooks (const tree_node *ptr, dump_flags_t options) |
| { |
| if (DECL_P (ptr)) |
| lang_hooks.print_decl (stderr, const_cast <tree_node*> (ptr), 0); |
| else if (TYPE_P (ptr)) |
| lang_hooks.print_type (stderr, const_cast <tree_node*> (ptr), 0); |
| else if (TREE_CODE (ptr) == IDENTIFIER_NODE) |
| lang_hooks.print_identifier (stderr, const_cast <tree_node*> (ptr), 0); |
| else |
| print_generic_expr (stderr, const_cast <tree_node*> (ptr), options); |
| fprintf (stderr, "\n"); |
| } |
| |
| DEBUG_FUNCTION void |
| debug (const tree_node &ref) |
| { |
| dump_tree_via_hooks (&ref, TDF_NONE); |
| } |
| |
| DEBUG_FUNCTION void |
| debug (const tree_node *ptr) |
| { |
| if (ptr) |
| debug (*ptr); |
| else |
| fprintf (stderr, "<nil>\n"); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_head (const tree_node &ref) |
| { |
| debug (ref); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_head (const tree_node *ptr) |
| { |
| if (ptr) |
| debug_head (*ptr); |
| else |
| fprintf (stderr, "<nil>\n"); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_body (const tree_node &ref) |
| { |
| if (TREE_CODE (&ref) == FUNCTION_DECL) |
| dump_function_to_file (const_cast <tree_node*> (&ref), stderr, TDF_NONE); |
| else |
| debug (ref); |
| } |
| |
| DEBUG_FUNCTION void |
| debug_body (const tree_node *ptr) |
| { |
| if (ptr) |
| debug_body (*ptr); |
| else |
| fprintf (stderr, "<nil>\n"); |
| } |
| |
| /* Print the vector of trees VEC on standard error, for debugging. |
| Most nodes referred to by this one are printed recursively |
| down to a depth of six. */ |
| |
| DEBUG_FUNCTION void |
| debug_raw (vec<tree, va_gc> &ref) |
| { |
| tree elt; |
| unsigned ix; |
| |
| /* Print the slot this node is in, and its code, and address. */ |
| fprintf (stderr, "<VEC"); |
| dump_addr (stderr, " ", ref.address ()); |
| |
| FOR_EACH_VEC_ELT (ref, ix, elt) |
| { |
| fprintf (stderr, "elt:%d ", ix); |
| debug_raw (elt); |
| } |
| } |
| |
| DEBUG_FUNCTION void |
| debug_raw (vec<tree, va_gc> *ptr) |
| { |
| if (ptr) |
| debug_raw (*ptr); |
| else |
| fprintf (stderr, "<nil>\n"); |
| } |
| |
| static void |
| debug_slim (tree t) |
| { |
| print_node_brief (stderr, "", t, 0); |
| } |
| |
| DEFINE_DEBUG_VEC (tree) |
| DEFINE_DEBUG_HASH_SET (tree) |