diff options
Diffstat (limited to 'gcc/tree-pretty-print.c')
-rw-r--r-- | gcc/tree-pretty-print.c | 2267 |
1 files changed, 2267 insertions, 0 deletions
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c new file mode 100644 index 00000000000..7eea529f063 --- /dev/null +++ b/gcc/tree-pretty-print.c @@ -0,0 +1,2267 @@ +/* Pretty formatting of GENERIC trees in C syntax. + Copyright (C) 2001, 2002, 2003 Free Software Foundation, Inc. + Adapted from c-pretty-print.c by Diego Novillo <dnovillo@redhat.com> + +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 2, 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 COPYING. If not, write to the Free +Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "errors.h" +#include "tree.h" +#include "diagnostic.h" +#include "real.h" +#include "hashtab.h" +#include "tree-flow.h" +#include "langhooks.h" +#include "tree-iterator.h" + +/* Local functions, macros and variables. */ +static int op_prio (tree); +static const char *op_symbol (tree); +static void pretty_print_string (pretty_printer *, const char*); +static void print_call_name (pretty_printer *, tree); +static void newline_and_indent (pretty_printer *, int); +static void maybe_init_pretty_print (FILE *); +static void print_declaration (pretty_printer *, tree, int, int); +static void print_struct_decl (pretty_printer *, tree, int, int); +static void do_niy (pretty_printer *, tree); +static void dump_vops (pretty_printer *, tree, int, int); +static void dump_generic_bb_buff (pretty_printer *, basic_block, int, int); + +#define INDENT(SPACE) do { \ + int i; for (i = 0; i<SPACE; i++) pp_space (buffer); } while (0) + +#define NIY do_niy(buffer,node) + +#define PRINT_FUNCTION_NAME(NODE) pp_printf \ + (buffer, "%s", TREE_CODE (NODE) == NOP_EXPR ? \ + (*lang_hooks.decl_printable_name) (TREE_OPERAND (NODE, 0), 1) : \ + (*lang_hooks.decl_printable_name) (NODE, 1)) + +#define MASK_POINTER(P) ((unsigned)((unsigned long)(P) & 0xffff)) + +static pretty_printer buffer; +static int initialized = 0; +static bool dumping_stmts; + +/* Try to print something for an unknown tree code. */ + +static void +do_niy (pretty_printer *buffer, tree node) +{ + int i, len; + + pp_string (buffer, "<<< Unknown tree: "); + pp_string (buffer, tree_code_name[(int) TREE_CODE (node)]); + + if (IS_EXPR_CODE_CLASS (TREE_CODE_CLASS (TREE_CODE (node)))) + { + len = first_rtl_op (TREE_CODE (node)); + for (i = 0; i < len; ++i) + { + newline_and_indent (buffer, 2); + dump_generic_node (buffer, TREE_OPERAND (node, i), 2, 0, false); + } + } + + pp_string (buffer, " >>>\n"); +} + +void +debug_generic_expr (tree t) +{ + print_generic_expr (stderr, t, TDF_VOPS|TDF_UID); + fprintf (stderr, "\n"); +} + +void +debug_generic_stmt (tree t) +{ + print_generic_stmt (stderr, t, TDF_VOPS|TDF_UID); + fprintf (stderr, "\n"); +} + +/* Prints declaration DECL to the FILE with details specified by FLAGS. */ +void +print_generic_decl (FILE *file, tree decl, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + print_declaration (&buffer, decl, 2, flags); + pp_write_text_to_stream (&buffer); +} + +/* Print tree T, and its successors, on file FILE. FLAGS specifies details + to show in the dump. See TDF_* in tree.h. */ + +void +print_generic_stmt (FILE *file, tree t, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + dump_generic_node (&buffer, t, 0, flags, true); + pp_flush (&buffer); +} + +/* Print tree T, and its successors, on file FILE. FLAGS specifies details + to show in the dump. See TDF_* in tree.h. The output is indented by + INDENT spaces. */ + +void +print_generic_stmt_indented (FILE *file, tree t, int flags, int indent) +{ + int i; + + maybe_init_pretty_print (file); + dumping_stmts = true; + + for (i = 0; i < indent; i++) + pp_space (&buffer); + dump_generic_node (&buffer, t, indent, flags, true); + pp_flush (&buffer); +} + +/* Print a single expression T on file FILE. FLAGS specifies details to show + in the dump. See TDF_* in tree.h. */ + +void +print_generic_expr (FILE *file, tree t, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = false; + dump_generic_node (&buffer, t, 0, flags, false); +} + +/* Dump the name of a _DECL node and its DECL_UID if TDF_UID is set + in FLAGS. */ + +static void +dump_decl_name (pretty_printer *buffer, tree node, int flags) +{ + if (DECL_NAME (node)) + pp_tree_identifier (buffer, DECL_NAME (node)); + + if ((flags & TDF_UID) + || DECL_NAME (node) == NULL_TREE) + { + if (TREE_CODE (node) == LABEL_DECL + && LABEL_DECL_UID (node) != -1) + pp_printf (buffer, "<L" HOST_WIDE_INT_PRINT_DEC ">", + LABEL_DECL_UID (node)); + else + pp_printf (buffer, "<D%u>", DECL_UID (node)); + } +} + +/* Dump the node NODE on the pretty_printer BUFFER, SPC spaces of indent. + FLAGS specifies details to show in the dump (see TDF_* in tree.h). If + IS_STMT is true, the object printed is considered to be a statement + and it is terminated by ';' if appropriate. */ + +int +dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags, + bool is_stmt) +{ + tree type; + tree op0, op1; + const char* str; + bool is_expr; + + if (node == NULL_TREE) + return spc; + + is_expr = EXPR_P (node); + + if (TREE_CODE (node) != ERROR_MARK + && is_gimple_stmt (node) + && (flags & TDF_VOPS) + && stmt_ann (node)) + dump_vops (buffer, node, spc, flags); + + if (dumping_stmts + && (flags & TDF_LINENO) + && EXPR_HAS_LOCATION (node)) + { + pp_character (buffer, '['); + if (EXPR_FILENAME (node)) + { + pp_string (buffer, EXPR_FILENAME (node)); + pp_string (buffer, " : "); + } + pp_decimal_int (buffer, EXPR_LINENO (node)); + pp_string (buffer, "] "); + } + + switch (TREE_CODE (node)) + { + case ERROR_MARK: + pp_string (buffer, "<<< error >>>"); + break; + + case IDENTIFIER_NODE: + pp_tree_identifier (buffer, node); + break; + + case TREE_LIST: + while (node && node != error_mark_node) + { + if (TREE_PURPOSE (node)) + { + dump_generic_node (buffer, TREE_PURPOSE (node), spc, flags, false); + pp_space (buffer); + } + dump_generic_node (buffer, TREE_VALUE (node), spc, flags, false); + node = TREE_CHAIN (node); + if (node && TREE_CODE (node) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + break; + + case TREE_VEC: + dump_generic_node (buffer, BINFO_TYPE (node), spc, flags, false); + break; + + case BLOCK: + NIY; + break; + + case VOID_TYPE: + case INTEGER_TYPE: + case REAL_TYPE: + case COMPLEX_TYPE: + case VECTOR_TYPE: + case ENUMERAL_TYPE: + case BOOLEAN_TYPE: + case CHAR_TYPE: + { + unsigned int quals = TYPE_QUALS (node); + char class; + + if (quals & TYPE_QUAL_CONST) + pp_string (buffer, "const "); + else if (quals & TYPE_QUAL_VOLATILE) + pp_string (buffer, "volatile "); + else if (quals & TYPE_QUAL_RESTRICT) + pp_string (buffer, "restrict "); + + class = TREE_CODE_CLASS (TREE_CODE (node)); + + if (class == 'd') + { + if (DECL_NAME (node)) + dump_decl_name (buffer, node, flags); + else + pp_string (buffer, "<unnamed type decl>"); + } + else if (class == 't') + { + if (TYPE_NAME (node)) + { + if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) + pp_tree_identifier (buffer, TYPE_NAME (node)); + else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL + && DECL_NAME (TYPE_NAME (node))) + dump_decl_name (buffer, TYPE_NAME (node), flags); + else + pp_string (buffer, "<unnamed type>"); + } + else + pp_string (buffer, "<unnamed type>"); + } + break; + } + + case POINTER_TYPE: + case REFERENCE_TYPE: + str = (TREE_CODE (node) == POINTER_TYPE ? "*" : "&"); + + if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE) + { + tree fnode = TREE_TYPE (node); + dump_generic_node (buffer, TREE_TYPE (fnode), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '('); + pp_string (buffer, str); + if (TYPE_NAME (node) && DECL_NAME (TYPE_NAME (node))) + dump_decl_name (buffer, TYPE_NAME (node), flags); + else + pp_printf (buffer, "<T%x>", TYPE_UID (node)); + + pp_character (buffer, ')'); + pp_space (buffer); + pp_character (buffer, '('); + /* Print the argument types. The last element in the list is a + VOID_TYPE. The following avoid to print the last element. */ + { + tree tmp = TYPE_ARG_TYPES (fnode); + while (tmp && TREE_CHAIN (tmp) && tmp != error_mark_node) + { + dump_generic_node (buffer, TREE_VALUE (tmp), spc, flags, false); + tmp = TREE_CHAIN (tmp); + if (TREE_CHAIN (tmp) && TREE_CODE (TREE_CHAIN (tmp)) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + } + pp_character (buffer, ')'); + } + else + { + unsigned int quals = TYPE_QUALS (node); + + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_space (buffer); + pp_string (buffer, str); + + if (quals & TYPE_QUAL_CONST) + pp_string (buffer, " const"); + else if (quals & TYPE_QUAL_VOLATILE) + pp_string (buffer, "volatile"); + else if (quals & TYPE_QUAL_RESTRICT) + pp_string (buffer, " restrict"); + } + break; + + case OFFSET_TYPE: + NIY; + break; + + case METHOD_TYPE: + dump_decl_name (buffer, TYPE_NAME (TYPE_METHOD_BASETYPE (node)), flags); + pp_string (buffer, "::"); + break; + + case FILE_TYPE: + NIY; + break; + + case ARRAY_TYPE: + { + tree tmp; + + /* Print the array type. */ + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + + /* Print the dimensions. */ + tmp = node; + while (tmp && TREE_CODE (tmp) == ARRAY_TYPE) + { + pp_character (buffer, '['); + if (TYPE_SIZE (tmp)) + { + tree size = TYPE_SIZE (tmp); + if (TREE_CODE (size) == INTEGER_CST) + pp_wide_integer (buffer, + TREE_INT_CST_LOW (TYPE_SIZE (tmp)) / + TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tmp)))); + else if (TREE_CODE (size) == MULT_EXPR) + dump_generic_node (buffer, TREE_OPERAND (size, 0), spc, flags, false); + /* else punt. */ + } + pp_character (buffer, ']'); + tmp = TREE_TYPE (tmp); + } + break; + } + + case SET_TYPE: + NIY; + break; + + case RECORD_TYPE: + case UNION_TYPE: + /* Print the name of the structure. */ + if (TREE_CODE (node) == RECORD_TYPE) + pp_string (buffer, "struct "); + else if (TREE_CODE (node) == UNION_TYPE) + pp_string (buffer, "union "); + + if (TYPE_NAME (node)) + dump_generic_node (buffer, TYPE_NAME (node), spc, flags, false); + else + print_struct_decl (buffer, node, spc, flags); + break; + + case QUAL_UNION_TYPE: + NIY; + break; + + + case LANG_TYPE: + NIY; + break; + + case INTEGER_CST: + if (TREE_CODE (TREE_TYPE (node)) == POINTER_TYPE) + { + /* In the case of a pointer, one may want to divide by the + size of the pointed-to type. Unfortunately, this not + straightforward. The C front-end maps expressions + + (int *) 5 + int *p; (p + 5) + + in such a way that the two INTEGER_CST nodes for "5" have + different values but identical types. In the latter + case, the 5 is multiplied by sizeof (int) in c-common.c + (pointer_int_sum) to convert it to a byte address, and + yet the type of the node is left unchanged. Argh. What + is consistent though is that the number value corresponds + to bytes (UNITS) offset. + + NB: Neither of the following divisors can be trivially + used to recover the original literal: + + TREE_INT_CST_LOW (TYPE_SIZE_UNIT (TREE_TYPE (node))) + TYPE_PRECISION (TREE_TYPE (TREE_TYPE (node))) */ + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + pp_string (buffer, "B"); /* pseudo-unit */ + } + else if (! host_integerp (node, 0)) + { + tree val = node; + + if (tree_int_cst_sgn (val) < 0) + { + pp_character (buffer, '-'); + val = build_int_2 (-TREE_INT_CST_LOW (val), + ~TREE_INT_CST_HIGH (val) + + !TREE_INT_CST_LOW (val)); + } + /* Would "%x%0*x" or "%x%*0x" get zero-padding on all + systems? */ + { + static char format[10]; /* "%x%09999x\0" */ + if (!format[0]) + sprintf (format, "%%x%%0%dx", HOST_BITS_PER_INT / 4); + sprintf (pp_buffer (buffer)->digit_buffer, format, + TREE_INT_CST_HIGH (val), + TREE_INT_CST_LOW (val)); + pp_string (buffer, pp_buffer (buffer)->digit_buffer); + } + } + else + pp_wide_integer (buffer, TREE_INT_CST_LOW (node)); + break; + + case REAL_CST: + /* Code copied from print_node. */ + { + REAL_VALUE_TYPE d; + if (TREE_OVERFLOW (node)) + pp_string (buffer, " overflow"); + +#if !defined(REAL_IS_NOT_DOUBLE) || defined(REAL_ARITHMETIC) + d = TREE_REAL_CST (node); + if (REAL_VALUE_ISINF (d)) + pp_string (buffer, " Inf"); + else if (REAL_VALUE_ISNAN (d)) + pp_string (buffer, " Nan"); + else + { + char string[100]; + real_to_decimal (string, &d, sizeof (string), 0, 1); + pp_string (buffer, string); + } +#else + { + HOST_WIDE_INT i; + unsigned char *p = (unsigned char *) &TREE_REAL_CST (node); + pp_string (buffer, "0x"); + for (i = 0; i < sizeof TREE_REAL_CST (node); i++) + output_formatted_integer (buffer, "%02x", *p++); + } +#endif + break; + } + + case COMPLEX_CST: + pp_string (buffer, "__complex__ ("); + dump_generic_node (buffer, TREE_REALPART (node), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_IMAGPART (node), spc, flags, false); + pp_string (buffer, ")"); + break; + + case STRING_CST: + pp_string (buffer, "\""); + pretty_print_string (buffer, TREE_STRING_POINTER (node)); + pp_string (buffer, "\""); + break; + + case VECTOR_CST: + { + tree elt; + pp_string (buffer, "{ "); + for (elt = TREE_VECTOR_CST_ELTS (node); elt; elt = TREE_CHAIN (elt)) + { + dump_generic_node (buffer, TREE_VALUE (elt), spc, flags, false); + if (TREE_CHAIN (elt)) + pp_string (buffer, ", "); + } + pp_string (buffer, " }"); + } + break; + + case FUNCTION_TYPE: + break; + + case FUNCTION_DECL: + case CONST_DECL: + dump_decl_name (buffer, node, flags); + break; + + case LABEL_DECL: + if (DECL_NAME (node)) + dump_decl_name (buffer, node, flags); + else if (LABEL_DECL_UID (node) != -1) + pp_printf (buffer, "<L" HOST_WIDE_INT_PRINT_DEC ">", + LABEL_DECL_UID (node)); + else + pp_printf (buffer, "<D%u>", DECL_UID (node)); + break; + + case TYPE_DECL: + if (strcmp (DECL_SOURCE_FILE (node), "<built-in>") == 0) + { + /* Don't print the declaration of built-in types. */ + break; + } + if (DECL_NAME (node)) + { + dump_decl_name (buffer, node, flags); + } + else + { + if (TYPE_METHODS (TREE_TYPE (node))) + { + /* The type is a c++ class: all structures have at least + 4 methods. */ + pp_string (buffer, "class "); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + } + else + { + pp_string (buffer, "struct "); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_character (buffer, ';'); + pp_newline (buffer); + } + } + break; + + case VAR_DECL: + case PARM_DECL: + case FIELD_DECL: + case NAMESPACE_DECL: + dump_decl_name (buffer, node, flags); + break; + + case RESULT_DECL: + pp_string (buffer, "<retval>"); + break; + + case COMPONENT_REF: + op0 = TREE_OPERAND (node, 0); + str = "."; + if (TREE_CODE (op0) == INDIRECT_REF) + { + op0 = TREE_OPERAND (op0, 0); + str = "->"; + } + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + pp_string (buffer, str); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + break; + + case BIT_FIELD_REF: + pp_string (buffer, "BIT_FIELD_REF <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + pp_string (buffer, ">"); + break; + + case BUFFER_REF: + NIY; + break; + + case ARRAY_REF: + op0 = TREE_OPERAND (node, 0); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + pp_character (buffer, '['); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, ']'); + break; + + case ARRAY_RANGE_REF: + NIY; + break; + + case CONSTRUCTOR: + { + tree lnode; + bool is_struct_init = FALSE; + pp_character (buffer, '{'); + lnode = CONSTRUCTOR_ELTS (node); + if (TREE_CODE (TREE_TYPE (node)) == RECORD_TYPE + || TREE_CODE (TREE_TYPE (node)) == UNION_TYPE) + is_struct_init = TRUE; + while (lnode && lnode != error_mark_node) + { + tree val; + if (TREE_PURPOSE (lnode) && is_struct_init) + { + pp_character (buffer, '.'); + dump_generic_node (buffer, TREE_PURPOSE (lnode), spc, flags, false); + pp_string (buffer, "="); + } + val = TREE_VALUE (lnode); + if (val && TREE_CODE (val) == ADDR_EXPR) + if (TREE_CODE (TREE_OPERAND (val, 0)) == FUNCTION_DECL) + val = TREE_OPERAND (val, 0); + if (val && TREE_CODE (val) == FUNCTION_DECL) + { + dump_decl_name (buffer, val, flags); + } + else + { + dump_generic_node (buffer, TREE_VALUE (lnode), spc, flags, false); + } + lnode = TREE_CHAIN (lnode); + if (lnode && TREE_CODE (lnode) == TREE_LIST) + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + pp_character (buffer, '}'); + } + break; + + case COMPOUND_EXPR: + { + tree *tp; + if (flags & TDF_SLIM) + { + pp_string (buffer, "<COMPOUND_EXPR>"); + break; + } + + dump_generic_node (buffer, TREE_OPERAND (node, 0), + spc, flags, dumping_stmts); + if (dumping_stmts) + newline_and_indent (buffer, spc); + else + { + pp_character (buffer, ','); + pp_space (buffer); + } + + for (tp = &TREE_OPERAND (node, 1); + TREE_CODE (*tp) == COMPOUND_EXPR; + tp = &TREE_OPERAND (*tp, 1)) + { + dump_generic_node (buffer, TREE_OPERAND (*tp, 0), + spc, flags, dumping_stmts); + if (dumping_stmts) + newline_and_indent (buffer, spc); + else + { + pp_character (buffer, ','); + pp_space (buffer); + } + } + + dump_generic_node (buffer, *tp, spc, flags, dumping_stmts); + } + break; + + case STATEMENT_LIST: + { + tree_stmt_iterator si; + bool first = true; + + if ((flags & TDF_SLIM) || !dumping_stmts) + { + pp_string (buffer, "<STATEMENT_LIST>"); + break; + } + + for (si = tsi_start (node); !tsi_end_p (si); tsi_next (&si)) + { + if (!first) + newline_and_indent (buffer, spc); + else + first = false; + dump_generic_node (buffer, tsi_stmt (si), spc, flags, true); + } + } + break; + + case MODIFY_EXPR: + case INIT_EXPR: + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '='); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + break; + + case TARGET_EXPR: + dump_generic_node (buffer, TYPE_NAME (TREE_TYPE (node)), spc, flags, false); + pp_character (buffer, '('); + dump_generic_node (buffer, TARGET_EXPR_INITIAL (node), spc, flags, false); + pp_character (buffer, ')'); + break; + + case COND_EXPR: + if (TREE_TYPE (node) == void_type_node) + { + pp_string (buffer, "if ("); + dump_generic_node (buffer, COND_EXPR_COND (node), spc, flags, false); + pp_character (buffer, ')'); + /* The lowered cond_exprs should always be printed in full. */ + if (COND_EXPR_THEN (node) + && TREE_CODE (COND_EXPR_THEN (node)) == GOTO_EXPR + && COND_EXPR_ELSE (node) + && TREE_CODE (COND_EXPR_ELSE (node)) == GOTO_EXPR) + { + pp_space (buffer); + dump_generic_node (buffer, COND_EXPR_THEN (node), 0, flags, true); + pp_string (buffer, " else "); + dump_generic_node (buffer, COND_EXPR_ELSE (node), 0, flags, true); + } + else if (!(flags & TDF_SLIM)) + { + /* Output COND_EXPR_THEN. */ + if (COND_EXPR_THEN (node)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, COND_EXPR_THEN (node), spc+4, + flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + + /* Output COND_EXPR_ELSE. */ + if (COND_EXPR_ELSE (node)) + { + newline_and_indent (buffer, spc); + pp_string (buffer, "else"); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, COND_EXPR_ELSE (node), spc+4, + flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + } + is_expr = false; + } + else + { + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_space (buffer); + pp_character (buffer, '?'); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_space (buffer); + pp_character (buffer, ':'); + pp_space (buffer); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + } + break; + + case BIND_EXPR: + pp_character (buffer, '{'); + if (!(flags & TDF_SLIM)) + { + if (BIND_EXPR_VARS (node)) + { + pp_newline (buffer); + + for (op0 = BIND_EXPR_VARS (node); op0; op0 = TREE_CHAIN (op0)) + { + print_declaration (buffer, op0, spc+2, flags); + pp_newline (buffer); + } + } + + newline_and_indent (buffer, spc+2); + dump_generic_node (buffer, BIND_EXPR_BODY (node), spc+2, flags, true); + newline_and_indent (buffer, spc); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case CALL_EXPR: + print_call_name (buffer, node); + + /* Print parameters. */ + pp_space (buffer); + pp_character (buffer, '('); + op1 = TREE_OPERAND (node, 1); + if (op1) + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ')'); + + op1 = TREE_OPERAND (node, 2); + if (op1) + { + pp_string (buffer, " [static-chain: "); + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ']'); + } + + if (CALL_EXPR_TAILCALL (node)) + pp_string (buffer, " [tail call]"); + break; + + case WITH_CLEANUP_EXPR: + NIY; + break; + + case CLEANUP_POINT_EXPR: + pp_string (buffer, "<<cleanup_point "); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">>"); + break; + + case PLACEHOLDER_EXPR: + NIY; + break; + + /* Binary arithmetic and logic expressions. */ + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + case BIT_AND_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + case EQ_EXPR: + case NE_EXPR: + case UNLT_EXPR: + case UNLE_EXPR: + case UNGT_EXPR: + case UNGE_EXPR: + case UNEQ_EXPR: + { + const char *op = op_symbol (node); + op0 = TREE_OPERAND (node, 0); + op1 = TREE_OPERAND (node, 1); + + /* When the operands are expressions with less priority, + keep semantics of the tree representation. */ + if (op_prio (op0) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, op0, spc, flags, false); + + pp_space (buffer); + pp_string (buffer, op); + pp_space (buffer); + + /* When the operands are expressions with less priority, + keep semantics of the tree representation. */ + if (op_prio (op1) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, op1, spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, op1, spc, flags, false); + } + break; + + /* Unary arithmetic and logic expressions. */ + case NEGATE_EXPR: + case BIT_NOT_EXPR: + case TRUTH_NOT_EXPR: + case ADDR_EXPR: + case REFERENCE_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case INDIRECT_REF: + if (TREE_CODE (node) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (node, 0)) == STRING_CST + || TREE_CODE (TREE_OPERAND (node, 0)) == FUNCTION_DECL)) + ; /* Do not output '&' for strings and function pointers. */ + else + pp_string (buffer, op_symbol (node)); + + if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + break; + + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + if (op_prio (TREE_OPERAND (node, 0)) < op_prio (node)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + } + else + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, op_symbol (node)); + break; + + case MIN_EXPR: + pp_string (buffer, "MIN_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, '>'); + break; + + case MAX_EXPR: + pp_string (buffer, "MAX_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, '>'); + break; + + case ABS_EXPR: + pp_string (buffer, "ABS_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case UNORDERED_EXPR: + NIY; + break; + + case ORDERED_EXPR: + NIY; + break; + + case IN_EXPR: + NIY; + break; + + case SET_LE_EXPR: + NIY; + break; + + case CARD_EXPR: + NIY; + break; + + case RANGE_EXPR: + NIY; + break; + + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case FLOAT_EXPR: + case CONVERT_EXPR: + case NOP_EXPR: + type = TREE_TYPE (node); + op0 = TREE_OPERAND (node, 0); + if (type != TREE_TYPE (op0)) + { + pp_character (buffer, '('); + dump_generic_node (buffer, type, spc, flags, false); + pp_string (buffer, ")"); + } + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, '('); + dump_generic_node (buffer, op0, spc, flags, false); + if (op_prio (op0) < op_prio (node)) + pp_character (buffer, ')'); + break; + + case VIEW_CONVERT_EXPR: + pp_string (buffer, "VIEW_CONVERT_EXPR<"); + dump_generic_node (buffer, TREE_TYPE (node), spc, flags, false); + pp_string (buffer, ">("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, ')'); + break; + + case NON_LVALUE_EXPR: + pp_string (buffer, "NON_LVALUE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case SAVE_EXPR: + pp_string (buffer, "SAVE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case UNSAVE_EXPR: + pp_string (buffer, "UNSAVE_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_character (buffer, '>'); + break; + + case RTL_EXPR: + NIY; + break; + + case ENTRY_VALUE_EXPR: + NIY; + break; + + case COMPLEX_EXPR: + pp_string (buffer, "COMPLEX_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ", "); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_string (buffer, ">"); + break; + + case CONJ_EXPR: + pp_string (buffer, "CONJ_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case REALPART_EXPR: + pp_string (buffer, "REALPART_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case IMAGPART_EXPR: + pp_string (buffer, "IMAGPART_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case VA_ARG_EXPR: + pp_string (buffer, "VA_ARG_EXPR <"); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ">"); + break; + + case TRY_FINALLY_EXPR: + case TRY_CATCH_EXPR: + pp_string (buffer, "try"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + newline_and_indent (buffer, spc); + pp_string (buffer, + (TREE_CODE (node) == TRY_CATCH_EXPR) ? "catch" : "finally"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case CATCH_EXPR: + pp_string (buffer, "catch ("); + dump_generic_node (buffer, CATCH_TYPES (node), spc+2, flags, false); + pp_string (buffer, ")"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, CATCH_BODY (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case EH_FILTER_EXPR: + pp_string (buffer, "<<<eh_filter ("); + dump_generic_node (buffer, EH_FILTER_TYPES (node), spc+2, flags, false); + pp_string (buffer, ")>>>"); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "{"); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, EH_FILTER_FAILURE (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_string (buffer, "}"); + is_expr = false; + break; + + case GOTO_SUBROUTINE_EXPR: + NIY; + break; + + case LABEL_EXPR: + op0 = TREE_OPERAND (node, 0); + /* If this is for break or continue, don't bother printing it. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + break; + } + dump_generic_node (buffer, op0, spc, flags, false); + pp_character (buffer, ':'); + if (DECL_NONLOCAL (op0)) + pp_string (buffer, " [non-local]"); + break; + + case LABELED_BLOCK_EXPR: + op0 = LABELED_BLOCK_LABEL (node); + /* If this is for break or continue, don't bother printing it. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + dump_generic_node (buffer, LABELED_BLOCK_BODY (node), spc, flags, false); + break; + } + } + dump_generic_node (buffer, LABELED_BLOCK_LABEL (node), spc, flags, false); + pp_string (buffer, ": {"); + if (!(flags & TDF_SLIM)) + newline_and_indent (buffer, spc+2); + dump_generic_node (buffer, LABELED_BLOCK_BODY (node), spc+2, flags, true); + if (!flags) + newline_and_indent (buffer, spc); + pp_character (buffer, '}'); + is_expr = false; + break; + + case EXIT_BLOCK_EXPR: + op0 = LABELED_BLOCK_LABEL (EXIT_BLOCK_LABELED_BLOCK (node)); + /* If this is for a break or continue, print it accordingly. */ + if (DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + pp_string (buffer, name); + break; + } + } + pp_string (buffer, "<<<exit block "); + dump_generic_node (buffer, op0, spc, flags, false); + pp_string (buffer, ">>>"); + break; + + case EXC_PTR_EXPR: + pp_string (buffer, "<<<exception object>>>"); + break; + + case FILTER_EXPR: + pp_string (buffer, "<<<filter object>>>"); + break; + + case LOOP_EXPR: + pp_string (buffer, "while (1)"); + if (!(flags & TDF_SLIM)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, LOOP_EXPR_BODY (node), spc+4, flags, true); + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case RETURN_EXPR: + pp_string (buffer, "return"); + op0 = TREE_OPERAND (node, 0); + if (op0) + { + pp_space (buffer); + if (TREE_CODE (op0) == MODIFY_EXPR) + dump_generic_node (buffer, TREE_OPERAND (op0, 1), spc, flags, false); + else + dump_generic_node (buffer, op0, spc, flags, false); + } + break; + + case EXIT_EXPR: + pp_string (buffer, "if ("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, ") break"); + break; + + case SWITCH_EXPR: + pp_string (buffer, "switch ("); + dump_generic_node (buffer, SWITCH_COND (node), spc, flags, false); + pp_character (buffer, ')'); + if (!(flags & TDF_SLIM)) + { + newline_and_indent (buffer, spc+2); + pp_character (buffer, '{'); + if (SWITCH_BODY (node)) + { + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, SWITCH_BODY (node), spc+4, flags, true); + } + else + { + tree vec = SWITCH_LABELS (node); + size_t i, n = TREE_VEC_LENGTH (vec); + for (i = 0; i < n; ++i) + { + tree elt = TREE_VEC_ELT (vec, i); + newline_and_indent (buffer, spc+4); + dump_generic_node (buffer, elt, spc+4, flags, false); + pp_string (buffer, " goto "); + dump_generic_node (buffer, CASE_LABEL (elt), spc+4, flags, true); + pp_semicolon (buffer); + } + } + newline_and_indent (buffer, spc+2); + pp_character (buffer, '}'); + } + is_expr = false; + break; + + case GOTO_EXPR: + op0 = GOTO_DESTINATION (node); + if (TREE_CODE (op0) != SSA_NAME + && DECL_P (op0) + && DECL_NAME (op0)) + { + const char *name = IDENTIFIER_POINTER (DECL_NAME (op0)); + if (strcmp (name, "break") == 0 + || strcmp (name, "continue") == 0) + { + pp_string (buffer, name); + break; + } + } + pp_string (buffer, "goto "); + dump_generic_node (buffer, op0, spc, flags, false); + break; + + case RESX_EXPR: + pp_string (buffer, "resx"); + /* ??? Any sensible way to present the eh region? */ + break; + + case ASM_EXPR: + pp_string (buffer, "__asm__"); + if (ASM_VOLATILE_P (node)) + pp_string (buffer, " __volatile__"); + pp_character (buffer, '('); + dump_generic_node (buffer, ASM_STRING (node), spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_OUTPUTS (node), spc, flags, false); + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_INPUTS (node), spc, flags, false); + if (ASM_CLOBBERS (node)) + { + pp_character (buffer, ':'); + dump_generic_node (buffer, ASM_CLOBBERS (node), spc, flags, false); + } + pp_string (buffer, ")"); + break; + + case CASE_LABEL_EXPR: + if (CASE_LOW (node) && CASE_HIGH (node)) + { + pp_string (buffer, "case "); + dump_generic_node (buffer, CASE_LOW (node), spc, flags, false); + pp_string (buffer, " ... "); + dump_generic_node (buffer, CASE_HIGH (node), spc, flags, false); + } + else if (CASE_LOW (node)) + { + pp_string (buffer, "case "); + dump_generic_node (buffer, CASE_LOW (node), spc, flags, false); + } + else + pp_string (buffer, "default "); + pp_character (buffer, ':'); + break; + + case VTABLE_REF: + pp_string (buffer, "VTABLE_REF <("); + dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false); + pp_string (buffer, "),"); + dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false); + pp_character (buffer, ','); + dump_generic_node (buffer, TREE_OPERAND (node, 2), spc, flags, false); + pp_character (buffer, '>'); + break; + + case EPHI_NODE: + { + int i; + + pp_string (buffer, " EPHI ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, " class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + if (EPHI_DOWNSAFE (node)) + pp_string (buffer, " downsafe"); + if (EPHI_CANT_BE_AVAIL (node)) + pp_string (buffer, " cant_be_avail"); + if (EPHI_STOPS (node)) + pp_string (buffer, " stops"); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + pp_character (buffer, ']'); + if (! (flags & TDF_SLIM)) + { + pp_string (buffer, " <"); + for (i = 0; i < EPHI_NUM_ARGS (node); i++) + { + if (EPHI_ARG_DEF (node, i)) + { + newline_and_indent (buffer, spc + 2); + pp_string (buffer, " edge "); + pp_decimal_int (buffer, EPHI_ARG_EDGE (node, i)->src->index); + pp_string (buffer, "->"); + pp_decimal_int (buffer, EPHI_ARG_EDGE (node, i)->dest->index); + pp_string (buffer, " [ "); + if (EPHI_ARG_HAS_REAL_USE (node, i)) + pp_string (buffer, " real use"); + if (EPHI_ARG_INJURED (node, i)) + pp_string (buffer, " injured"); + if (EPHI_ARG_STOPS (node, i)) + pp_string (buffer, " stops"); + pp_string (buffer, " ] "); + pp_string (buffer, " defined by:"); + dump_generic_node (buffer, EPHI_ARG_DEF (node, i), + spc + 4, flags | TDF_SLIM, false); + } + } + } + pp_string (buffer, " >"); + } + break; + case EEXIT_NODE: + case EKILL_NODE: + if (TREE_CODE (node) == EEXIT_NODE) + pp_string (buffer, "EEXIT ("); + else if (TREE_CODE (node) == EKILL_NODE) + pp_string (buffer, "EKILL ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, "class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + pp_character (buffer, ']'); + break; + case EUSE_NODE: + pp_string (buffer, " EUSE ("); + dump_generic_node (buffer, EREF_NAME (node), spc, flags, false); + + pp_string (buffer, ") "); + pp_character (buffer, '['); + pp_string (buffer, "class:"); + pp_decimal_int (buffer, EREF_CLASS (node)); + pp_string (buffer, " phiop:"); + pp_decimal_int (buffer, EUSE_PHIOP (node)); + pp_string (buffer, " bb:"); + pp_decimal_int (buffer, bb_for_stmt (node)->index); + if (EUSE_LVAL (node)) + pp_string (buffer, " left-occurrence"); + pp_string (buffer, " ]"); + + break; + case PHI_NODE: + { + int i; + + dump_generic_node (buffer, PHI_RESULT (node), spc, flags, false); + pp_string (buffer, " = PHI <"); + for (i = 0; i < PHI_NUM_ARGS (node); i++) + { + dump_generic_node (buffer, PHI_ARG_DEF (node, i), spc, flags, false); + pp_string (buffer, "("); + pp_decimal_int (buffer, PHI_ARG_EDGE (node, i)->src->index); + pp_string (buffer, ")"); + if (i < PHI_NUM_ARGS (node) - 1) + pp_string (buffer, ", "); + } + pp_string (buffer, ">;"); + } + break; + + case SSA_NAME: + dump_generic_node (buffer, SSA_NAME_VAR (node), spc, flags, false); + pp_string (buffer, "_"); + pp_decimal_int (buffer, SSA_NAME_VERSION (node)); + break; + + default: + NIY; + } + + if (is_stmt && is_expr) + pp_semicolon (buffer); + pp_write_text_to_stream (buffer); + + return spc; +} + +/* Print the declaration of a variable. */ + +static void +print_declaration (pretty_printer *buffer, tree t, int spc, int flags) +{ + /* Don't print type declarations. */ + if (TREE_CODE (t) == TYPE_DECL) + return; + + INDENT (spc); + + if (DECL_REGISTER (t)) + pp_string (buffer, "register "); + + if (TREE_PUBLIC (t) && DECL_EXTERNAL (t)) + pp_string (buffer, "extern "); + else if (TREE_STATIC (t)) + pp_string (buffer, "static "); + + /* Print the type and name. */ + if (TREE_CODE (TREE_TYPE (t)) == ARRAY_TYPE) + { + tree tmp; + + /* Print array's type. */ + tmp = TREE_TYPE (t); + while (TREE_CODE (TREE_TYPE (tmp)) == ARRAY_TYPE) + tmp = TREE_TYPE (tmp); + dump_generic_node (buffer, TREE_TYPE (tmp), spc, flags, false); + + /* Print variable's name. */ + pp_space (buffer); + dump_generic_node (buffer, t, spc, flags, false); + + /* Print the dimensions. */ + tmp = TREE_TYPE (t); + while (TREE_CODE (tmp) == ARRAY_TYPE) + { + pp_character (buffer, '['); + if (TYPE_DOMAIN (tmp)) + { + if (TREE_CODE (TYPE_SIZE (tmp)) == INTEGER_CST) + pp_wide_integer (buffer, + TREE_INT_CST_LOW (TYPE_SIZE (tmp)) / + TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (tmp)))); + else + dump_generic_node (buffer, TYPE_SIZE_UNIT (tmp), spc, flags, + false); + } + pp_character (buffer, ']'); + tmp = TREE_TYPE (tmp); + } + } + else + { + /* Print type declaration. */ + dump_generic_node (buffer, TREE_TYPE (t), spc, flags, false); + + /* Print variable's name. */ + pp_space (buffer); + dump_generic_node (buffer, t, spc, flags, false); + } + + /* The initial value of a function serves to determine wether the function + is declared or defined. So the following does not apply to function + nodes. */ + if (TREE_CODE (t) != FUNCTION_DECL) + { + /* Print the initial value. */ + if (DECL_INITIAL (t)) + { + pp_space (buffer); + pp_character (buffer, '='); + pp_space (buffer); + dump_generic_node (buffer, DECL_INITIAL (t), spc, flags, false); + } + } + + pp_character (buffer, ';'); +} + + +/* Prints a structure: name, fields, and methods. + FIXME: Still incomplete. */ + +static void +print_struct_decl (pretty_printer *buffer, tree node, int spc, int flags) +{ + /* Print the name of the structure. */ + if (TYPE_NAME (node)) + { + INDENT (spc); + if (TREE_CODE (node) == RECORD_TYPE) + pp_string (buffer, "struct "); + else if (TREE_CODE (node) == UNION_TYPE) + pp_string (buffer, "union "); + else + NIY; + dump_generic_node (buffer, TYPE_NAME (node), spc, 0, false); + } + + /* Print the contents of the structure. */ + pp_newline (buffer); + INDENT (spc); + pp_character (buffer, '{'); + pp_newline (buffer); + + /* Print the fields of the structure. */ + { + tree tmp; + tmp = TYPE_FIELDS (node); + while (tmp) + { + /* Avoid to print recursively the structure. */ + /* FIXME : Not implemented correctly..., + what about the case when we have a cycle in the contain graph? ... + Maybe this could be solved by looking at the scope in which the + structure was declared. */ + if (TREE_TYPE (tmp) != node + || (TREE_CODE (TREE_TYPE (tmp)) == POINTER_TYPE && + TREE_TYPE (TREE_TYPE (tmp)) != node)) + { + print_declaration (buffer, tmp, spc+2, flags); + pp_newline (buffer); + } + else + { + + } + tmp = TREE_CHAIN (tmp); + } + } + INDENT (spc); + pp_character (buffer, '}'); +} + +/* Return the priority of the operator OP. + + From lowest to highest precedence with either left-to-right (L-R) + or right-to-left (R-L) associativity]: + + 1 [L-R] , + 2 [R-L] = += -= *= /= %= &= ^= |= <<= >>= + 3 [R-L] ?: + 4 [L-R] || + 5 [L-R] && + 6 [L-R] | + 7 [L-R] ^ + 8 [L-R] & + 9 [L-R] == != + 10 [L-R] < <= > >= + 11 [L-R] << >> + 12 [L-R] + - + 13 [L-R] * / % + 14 [R-L] ! ~ ++ -- + - * & (type) sizeof + 15 [L-R] fn() [] -> . + + unary +, - and * have higher precedence than the corresponding binary + operators. */ + +static int +op_prio (tree op) +{ + if (op == NULL) + return 9999; + + switch (TREE_CODE (op)) + { + case TREE_LIST: + case COMPOUND_EXPR: + case BIND_EXPR: + return 1; + + case MODIFY_EXPR: + case INIT_EXPR: + return 2; + + case COND_EXPR: + return 3; + + case TRUTH_OR_EXPR: + case TRUTH_ORIF_EXPR: + return 4; + + case TRUTH_AND_EXPR: + case TRUTH_ANDIF_EXPR: + return 5; + + case BIT_IOR_EXPR: + return 6; + + case BIT_XOR_EXPR: + case TRUTH_XOR_EXPR: + return 7; + + case BIT_AND_EXPR: + return 8; + + case EQ_EXPR: + case NE_EXPR: + return 9; + + case LT_EXPR: + case LE_EXPR: + case GT_EXPR: + case GE_EXPR: + return 10; + + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case LROTATE_EXPR: + case RROTATE_EXPR: + return 11; + + case PLUS_EXPR: + case MINUS_EXPR: + return 12; + + case MULT_EXPR: + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + return 13; + + case TRUTH_NOT_EXPR: + case BIT_NOT_EXPR: + case POSTINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case PREDECREMENT_EXPR: + case NEGATE_EXPR: + case INDIRECT_REF: + case ADDR_EXPR: + case FLOAT_EXPR: + case NOP_EXPR: + case CONVERT_EXPR: + case FIX_TRUNC_EXPR: + case FIX_CEIL_EXPR: + case FIX_FLOOR_EXPR: + case FIX_ROUND_EXPR: + case TARGET_EXPR: + return 14; + + case CALL_EXPR: + case ARRAY_REF: + case COMPONENT_REF: + return 15; + + /* Special expressions. */ + case MIN_EXPR: + case MAX_EXPR: + case ABS_EXPR: + case REALPART_EXPR: + case IMAGPART_EXPR: + return 16; + + case SAVE_EXPR: + case NON_LVALUE_EXPR: + return op_prio (TREE_OPERAND (op, 0)); + + default: + /* Return an arbitrarily high precedence to avoid surrounding single + VAR_DECLs in ()s. */ + return 9999; + } +} + + +/* Return the symbol associated with operator OP. */ + +static const char * +op_symbol (tree op) +{ + if (op == NULL) + abort (); + + switch (TREE_CODE (op)) + { + case MODIFY_EXPR: + return "="; + + case TRUTH_OR_EXPR: + case TRUTH_ORIF_EXPR: + return "||"; + + case TRUTH_AND_EXPR: + case TRUTH_ANDIF_EXPR: + return "&&"; + + case BIT_IOR_EXPR: + return "|"; + + case TRUTH_XOR_EXPR: + case BIT_XOR_EXPR: + return "^"; + + case ADDR_EXPR: + case BIT_AND_EXPR: + return "&"; + + case EQ_EXPR: + case UNEQ_EXPR: + return "=="; + + case NE_EXPR: + return "!="; + + case LT_EXPR: + case UNLT_EXPR: + return "<"; + + case LE_EXPR: + case UNLE_EXPR: + return "<="; + + case GT_EXPR: + case UNGT_EXPR: + return ">"; + + case GE_EXPR: + case UNGE_EXPR: + return ">="; + + case LSHIFT_EXPR: + return "<<"; + + case RSHIFT_EXPR: + return ">>"; + + case PLUS_EXPR: + return "+"; + + case NEGATE_EXPR: + case MINUS_EXPR: + return "-"; + + case BIT_NOT_EXPR: + return "~"; + + case TRUTH_NOT_EXPR: + return "!"; + + case MULT_EXPR: + case INDIRECT_REF: + return "*"; + + case TRUNC_DIV_EXPR: + case CEIL_DIV_EXPR: + case FLOOR_DIV_EXPR: + case ROUND_DIV_EXPR: + case RDIV_EXPR: + case EXACT_DIV_EXPR: + return "/"; + + case TRUNC_MOD_EXPR: + case CEIL_MOD_EXPR: + case FLOOR_MOD_EXPR: + case ROUND_MOD_EXPR: + return "%"; + + case PREDECREMENT_EXPR: + return " --"; + + case PREINCREMENT_EXPR: + return " ++"; + + case POSTDECREMENT_EXPR: + return "-- "; + + case POSTINCREMENT_EXPR: + return "++ "; + + case REFERENCE_EXPR: + return ""; + + default: + return "<<< ??? >>>"; + } +} + +/* Prints the name of a CALL_EXPR. */ + +static void +print_call_name (pretty_printer *buffer, tree node) +{ + tree op0; + + if (TREE_CODE (node) != CALL_EXPR) + abort (); + + op0 = TREE_OPERAND (node, 0); + + if (TREE_CODE (op0) == NON_LVALUE_EXPR) + op0 = TREE_OPERAND (op0, 0); + + switch (TREE_CODE (op0)) + { + case VAR_DECL: + case PARM_DECL: + PRINT_FUNCTION_NAME (op0); + break; + + case ADDR_EXPR: + case INDIRECT_REF: + case NOP_EXPR: + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + break; + + case COND_EXPR: + pp_string (buffer, "("); + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + pp_string (buffer, ") ? "); + dump_generic_node (buffer, TREE_OPERAND (op0, 1), 0, 0, false); + pp_string (buffer, " : "); + dump_generic_node (buffer, TREE_OPERAND (op0, 2), 0, 0, false); + break; + + case COMPONENT_REF: + /* The function is a pointer contained in a structure. */ + if (TREE_CODE (TREE_OPERAND (op0, 0)) == INDIRECT_REF || + TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL) + PRINT_FUNCTION_NAME (TREE_OPERAND (op0, 1)); + else + dump_generic_node (buffer, TREE_OPERAND (op0, 0), 0, 0, false); + /* else + We can have several levels of structures and a function + pointer inside. This is not implemented yet... */ + /* NIY;*/ + break; + + case ARRAY_REF: + if (TREE_CODE (TREE_OPERAND (op0, 0)) == VAR_DECL) + PRINT_FUNCTION_NAME (TREE_OPERAND (op0, 0)); + else + dump_generic_node (buffer, op0, 0, 0, false); + break; + + case SSA_NAME: + dump_generic_node (buffer, op0, 0, 0, false); + break; + + default: + NIY; + } +} + +/* Parses the string STR and replaces new-lines by '\n', tabs by '\t', ... */ + +static void +pretty_print_string (pretty_printer *buffer, const char *str) +{ + if (str == NULL) + return; + + while (*str) + { + switch (str[0]) + { + case '\b': + pp_string (buffer, "\\b"); + break; + + case '\f': + pp_string (buffer, "\\f"); + break; + + case '\n': + pp_string (buffer, "\\n"); + break; + + case '\r': + pp_string (buffer, "\\r"); + break; + + case '\t': + pp_string (buffer, "\\t"); + break; + + case '\v': + pp_string (buffer, "\\v"); + break; + + case '\\': + pp_string (buffer, "\\\\"); + break; + + case '\"': + pp_string (buffer, "\\\""); + break; + + case '\'': + pp_string (buffer, "\\'"); + break; + + case '\0': + pp_string (buffer, "\\0"); + break; + + case '\1': + pp_string (buffer, "\\1"); + break; + + case '\2': + pp_string (buffer, "\\2"); + break; + + case '\3': + pp_string (buffer, "\\3"); + break; + + case '\4': + pp_string (buffer, "\\4"); + break; + + case '\5': + pp_string (buffer, "\\5"); + break; + + case '\6': + pp_string (buffer, "\\6"); + break; + + case '\7': + pp_string (buffer, "\\7"); + break; + + default: + pp_character (buffer, str[0]); + break; + } + str++; + } +} + +static void +maybe_init_pretty_print (FILE *file) +{ + if (!initialized) + { + pp_construct (&buffer, /* prefix */NULL, /* line-width */0); + pp_needs_newline (&buffer) = true; + initialized = 1; + } + + buffer.buffer->stream = file; +} + +static void +newline_and_indent (pretty_printer *buffer, int spc) +{ + pp_newline (buffer); + INDENT (spc); +} + +static void +dump_vops (pretty_printer *buffer, tree stmt, int spc, int flags) +{ + size_t i; + stmt_ann_t ann = stmt_ann (stmt); + vdef_optype vdefs = VDEF_OPS (ann); + vuse_optype vuses = VUSE_OPS (ann); + + for (i = 0; i < NUM_VDEFS (vdefs); i++) + { + pp_string (buffer, "# "); + dump_generic_node (buffer, VDEF_RESULT (vdefs, i), spc + 2, flags, false); + pp_string (buffer, " = VDEF <"); + dump_generic_node (buffer, VDEF_OP (vdefs, i), spc + 2, flags, false); + pp_string (buffer, ">;"); + newline_and_indent (buffer, spc); + } + + for (i = 0; i < NUM_VUSES (vuses); i++) + { + tree vuse = VUSE_OP (vuses, i); + pp_string (buffer, "# VUSE <"); + dump_generic_node (buffer, vuse, spc + 2, flags, false); + pp_string (buffer, ">;"); + newline_and_indent (buffer, spc); + } +} + +/* Dumps basic block BB to FILE with details described by FLAGS and + indented by INDENT spaces. */ + +void +dump_generic_bb (FILE *file, basic_block bb, int indent, int flags) +{ + maybe_init_pretty_print (file); + dumping_stmts = true; + dump_generic_bb_buff (&buffer, bb, indent, flags); + pp_flush (&buffer); +} + +/* Dumps header of basic block BB to buffer BUFFER indented by INDENT + spaces and details described by flags. */ + +static void +dump_bb_header (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + edge e; + tree stmt; + + if (flags & TDF_BLOCKS) + { + INDENT (indent); + pp_string (buffer, "# BLOCK "); + pp_decimal_int (buffer, bb->index); + + if (flags & TDF_LINENO) + { + block_stmt_iterator bsi; + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + if (get_lineno (bsi_stmt (bsi)) != -1) + { + pp_string (buffer, ", starting at line "); + pp_decimal_int (buffer, get_lineno (bsi_stmt (bsi))); + break; + } + } + newline_and_indent (buffer, indent); + + pp_string (buffer, "# PRED:"); + pp_write_text_to_stream (buffer); + for (e = bb->pred; e; e = e->pred_next) + if (flags & TDF_SLIM) + { + pp_string (buffer, " "); + if (e->src == ENTRY_BLOCK_PTR) + pp_string (buffer, "ENTRY"); + else + pp_decimal_int (buffer, e->src->index); + } + else + dump_edge_info (buffer->buffer->stream, e, 0); + pp_newline (buffer); + } + else + { + stmt = first_stmt (bb); + if (!stmt || TREE_CODE (stmt) != LABEL_EXPR) + { + INDENT (indent - 2); + pp_string (buffer, "<bb "); + pp_decimal_int (buffer, bb->index); + pp_string (buffer, ">:"); + pp_newline (buffer); + } + } +} + +/* Dumps end of basic block BB to buffer BUFFER indented by INDENT + spaces. */ + +static void +dump_bb_end (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + edge e; + + INDENT (indent); + pp_string (buffer, "# SUCC:"); + pp_write_text_to_stream (buffer); + for (e = bb->succ; e; e = e->succ_next) + if (flags & TDF_SLIM) + { + pp_string (buffer, " "); + if (e->dest == EXIT_BLOCK_PTR) + pp_string (buffer, "EXIT"); + else + pp_decimal_int (buffer, e->dest->index); + } + else + dump_edge_info (buffer->buffer->stream, e, 1); + pp_newline (buffer); +} + +/* Dumps phi nodes of basic block BB to buffer BUFFER with details described by + FLAGS indented by INDENT spaces. */ + +static void +dump_phi_nodes (pretty_printer *buffer, basic_block bb, int indent, int flags) +{ + tree phi = phi_nodes (bb); + if (!phi) + return; + + for (; phi; phi = TREE_CHAIN (phi)) + { + if (is_gimple_reg (PHI_RESULT (phi)) || (flags & TDF_VOPS)) + { + INDENT (indent); + pp_string (buffer, "# "); + dump_generic_node (buffer, phi, indent, flags, false); + pp_newline (buffer); + } + } +} + +/* Dump jump to basic block BB that is represented implicitly in the cfg + to BUFFER. */ + +static void +pp_cfg_jump (pretty_printer *buffer, basic_block bb) +{ + tree stmt; + + stmt = first_stmt (bb); + + pp_string (buffer, "goto <bb "); + pp_decimal_int (buffer, bb->index); + pp_string (buffer, ">"); + if (stmt && TREE_CODE (stmt) == LABEL_EXPR) + { + pp_string (buffer, " ("); + dump_generic_node (buffer, LABEL_EXPR_LABEL (stmt), 0, 0, false); + pp_string (buffer, ")"); + } + pp_semicolon (buffer); +} + +/* Dump edges represented implicitly in basic block BB to BUFFER, indented + by INDENT spaces, with details given by FLAGS. */ + +static void +dump_implicit_edges (pretty_printer *buffer, basic_block bb, int indent) +{ + edge e; + + /* If there is a fallthru edge, we may need to add an artificial goto to the + dump. */ + for (e = bb->succ; e; e = e->succ_next) + if (e->flags & EDGE_FALLTHRU) + break; + if (e && e->dest != bb->next_bb) + { + INDENT (indent); + pp_cfg_jump (buffer, e->dest); + pp_newline (buffer); + } +} + +/* Dumps basic block BB to buffer BUFFER with details described by FLAGS and + indented by INDENT spaces. */ + +static void +dump_generic_bb_buff (pretty_printer *buffer, basic_block bb, + int indent, int flags) +{ + block_stmt_iterator bsi; + tree stmt; + int label_indent = indent - 2; + + if (label_indent < 0) + label_indent = 0; + + dump_bb_header (buffer, bb, indent, flags); + + if (bb_ann (bb)) + dump_phi_nodes (buffer, bb, indent, flags); + + for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi)) + { + int curr_indent; + + stmt = bsi_stmt (bsi); + + curr_indent = TREE_CODE (stmt) == LABEL_EXPR ? label_indent : indent; + + INDENT (curr_indent); + dump_generic_node (buffer, stmt, curr_indent, flags, true); + pp_newline (buffer); + } + + dump_implicit_edges (buffer, bb, indent); + + if (flags & TDF_BLOCKS) + dump_bb_end (buffer, bb, indent, flags); +} |