/* Prints out tree in human readable form - GCC
Copyright (C) 1990-2020 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_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)
{
call_expr_arg_iterator iter;
tree arg;
print_node (file, "fn", CALL_EXPR_FN (node), indent + 4);
print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node),
indent + 4);
i = 0;
FOR_EACH_CALL_EXPR_ARG (arg, iter, node)
{
/* Buffer big enough to format a 32-bit UINT_MAX into, plus
the text. */
char temp[15];
sprintf (temp, "arg:%u", i);
print_node (file, temp, arg, indent + 4);
i++;
}
}
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_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)