From: Diego Novillo Date: Fri, 14 May 2004 02:29:32 +0000 (+0000) Subject: tree-gimple.c: Rename from tree-simple.c. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=eadf906f463167f90f23bed5d3bb56026a4bfc33;p=gcc.git tree-gimple.c: Rename from tree-simple.c. * tree-gimple.c: Rename from tree-simple.c. * tree-gimple.h: Rename from tree-simple.h. * c-gimplify.c: Rename from c-simplify.c * Makefile.in, c-decl.c, gimple-low.c, gimplify.c, langhooks.c, tree-alias-ander.c, tree-alias-common.c, tree-complex.c, tree-dfa.c, tree-flow.h, tree-inline.c, tree-into-ssa.c, tree-iterator.c, tree-mudflap.c, tree-nested.c, tree-nomudflap.c, tree-outof-ssa.c, tree-sra.c, tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-copyrename.c, tree-ssa-dce.c, tree-ssa-live.c, tree-ssa-pre.c, tree-ssa.c: Update. cp/ChangeLog * cp-gimplify.c: Rename from cp-simplify.c. * Make-lang.in, optimize.c: Update. fortran/ChangeLog * Make-lang.in, f95-lang.c, trans-array.c, trans-decl.c, trans-expr.c, trans-intrinsic.c, trans-io.c, trans-stmt.c, trans.c: Rename tree-simple.[ch] to tree-gimple.[ch]. java/ChangeLog * Make-lang.in, expr.c, java-gimplify.c: Rename tree-simple.[ch] to tree-gimple.[ch]. From-SVN: r81829 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 28ff3c0cd88..433d599a6cd 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2004-05-13 Diego Novillo + + * tree-gimple.c: Rename from tree-simple.c. + * tree-gimple.h: Rename from tree-simple.h. + * c-gimplify.c: Rename from c-simplify.c + * Makefile.in, c-decl.c, gimple-low.c, gimplify.c, + langhooks.c, tree-alias-ander.c, tree-alias-common.c, + tree-complex.c, tree-dfa.c, tree-flow.h, tree-inline.c, + tree-into-ssa.c, tree-iterator.c, tree-mudflap.c, + tree-nested.c, tree-nomudflap.c, tree-outof-ssa.c, tree-sra.c, + tree-ssa-alias.c, tree-ssa-ccp.c, tree-ssa-copyrename.c, + tree-ssa-dce.c, tree-ssa-live.c, tree-ssa-pre.c, tree-ssa.c: + Update. + 2004-05-14 Ranjit Mathew * doc/sourcebuild.texi: Mention libbanshee and libmudflap. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index bfeaa0c37ca..5379c8e59d4 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -702,9 +702,9 @@ SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h PREDICT_H = predict.h predict.def CPPLIB_H = cpplib.h line-map.h TREE_DUMP_H = tree-dump.h $(SPLAY_TREE_H) -TREE_SIMPLE_H = tree-simple.h tree-iterator.h +TREE_GIMPLE_H = tree-gimple.h tree-iterator.h TREE_FLOW_H = tree-flow.h tree-flow-inline.h tree-ssa-operands.h \ - bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_SIMPLE_H) \ + bitmap.h $(BASIC_BLOCK_H) hard-reg-set.h $(TREE_GIMPLE_H) \ $(HASHTAB_H) PRETTY_PRINT_H = pretty-print.h input.h $(OBSTACK_H) DIAGNOSTIC_H = diagnostic.h diagnostic.def $(PRETTY_PRINT_H) @@ -859,7 +859,7 @@ C_AND_OBJC_OBJS = attribs.o c-errors.o c-lex.o c-pragma.o c-decl.o c-typeck.o \ c-convert.o c-aux-info.o c-common.o c-opts.o c-format.o c-semantics.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ c-objc-common.o c-dump.o c-pch.o $(C_TARGET_OBJS) \ - c-simplify.o tree-mudflap.o c-mudflap.o c-pretty-print.o + c-gimplify.o tree-mudflap.o c-mudflap.o c-pretty-print.o # Language-specific object files for C. C_OBJS = c-parse.o c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) @@ -867,7 +867,7 @@ C_OBJS = c-parse.o c-lang.o stub-objc.o $(C_AND_OBJC_OBJS) # Language-independent object files. OBJS-common = \ - tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-simple.o \ + tree-cfg.o tree-dfa.o tree-eh.o tree-ssa.o tree-optimize.o tree-gimple.o \ tree-alias-type.o gimplify.o tree-pretty-print.o tree-into-ssa.o \ tree-outof-ssa.o tree-alias-common.o tree-ssa-ccp.o \ @ANDER@ tree-ssa-dce.o tree-ssa-copy.o tree-nrv.o tree-ssa-copyrename.o \ @@ -1545,7 +1545,7 @@ tree-inline.o : tree-inline.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(TREE_H) $(RTL_H) $(EXPR_H) flags.h $(PARAMS_H) input.h insn-config.h \ $(INTEGRATE_H) $(VARRAY_H) $(HASHTAB_H) $(SPLAY_TREE_H) toplev.h \ langhooks.h $(C_COMMON_H) tree-inline.h cgraph.h intl.h function.h \ - $(TREE_SIMPLE_H) + $(TREE_GIMPLE_H) print-tree.o : print-tree.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ $(GGC_H) langhooks.h real.h stor-layout.o : stor-layout.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ @@ -1622,9 +1622,9 @@ tree-tailcall.o : tree-tailcall.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(TREE_DUMP_H) diagnostic.h except.h tree-pass.h flags.h langhooks.h tree-nested.o: tree-nested.c $(CONFIG_H) $(SYSTEM_H) $(TM_H) $(TREE_H) \ $(RTL_H) $(TM_P_H) function.h tree-dump.h tree-inline.h tree-iterator.h \ - tree-simple.h cgraph.h $(EXPR_H) langhooks.h $(GGC_H) gt-tree-nested.h + tree-gimple.h cgraph.h $(EXPR_H) langhooks.h $(GGC_H) gt-tree-nested.h tree-iterator.o : tree-iterator.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) \ - coretypes.h $(GGC_H) tree-iterator.h tree-simple.h gt-tree-iterator.h + coretypes.h $(GGC_H) tree-iterator.h tree-gimple.h gt-tree-iterator.h tree-dfa.o : tree-dfa.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \ $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) output.h diagnostic.h \ errors.h tree-inline.h $(HASHTAB_H) flags.h function.h $(TIMEVAR_H) \ @@ -1650,32 +1650,32 @@ tree-optimize.o : tree-optimize.c $(TREE_FLOW_H) $(CONFIG_H) \ $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) toplev.h function.h \ langhooks.h flags.h cgraph.h tree-inline.h tree-mudflap.h $(GGC_H) \ cgraph.h tree-pass.h -c-simplify.o : c-simplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ - $(C_TREE_H) $(C_COMMON_H) diagnostic.h $(TREE_SIMPLE_H) varray.h flags.h \ +c-gimplify.o : c-gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ + $(C_TREE_H) $(C_COMMON_H) diagnostic.h $(TREE_GIMPLE_H) varray.h flags.h \ langhooks.h toplev.h rtl.h $(TREE_FLOW_H) langhooks-def.h \ $(TM_H) coretypes.h $(C_PRETTY_PRINT_H) cgraph.h gimplify.o : gimplify.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ - diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ + diagnostic.h $(TREE_GIMPLE_H) tree-inline.h varray.h langhooks.h \ langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ flags.h $(RTL_H) function.h $(EXPR_H) output.h $(GGC_H) gt-gimplify.h gimple-low.o : gimple-low.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) errors.h \ - diagnostic.h $(TREE_SIMPLE_H) tree-inline.h varray.h langhooks.h \ + diagnostic.h $(TREE_GIMPLE_H) tree-inline.h varray.h langhooks.h \ langhooks-def.h $(TREE_FLOW_H) $(TIMEVAR_H) $(TM_H) coretypes.h except.h \ flags.h $(RTL_H) function.h tree-pass.h tree-browser.o : tree-browser.c tree-browser.def $(CONFIG_H) $(SYSTEM_H) \ $(TREE_H) errors.h tree-inline.h diagnostic.h $(HASHTAB_H) \ $(TM_H) coretypes.h -tree-simple.o : tree-simple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ - $(RTL_H) $(TREE_SIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) +tree-gimple.o : tree-gimple.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(EXPR_H) \ + $(RTL_H) $(TREE_GIMPLE_H) $(TM_H) coretypes.h bitmap.h $(GGC_H) tree-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ - $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_GIMPLE_H) diagnostic.h $(HASHTAB_H) \ output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h \ $(TREE_DUMP_H) tree-pass.h c-mudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ - $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_GIMPLE_H) diagnostic.h $(HASHTAB_H) \ output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h tree-nomudflap.o : $(CONFIG_H) errors.h $(SYSTEM_H) $(TREE_H) tree-inline.h \ - $(C_TREE_H) $(C_COMMON_H) $(TREE_SIMPLE_H) diagnostic.h $(HASHTAB_H) \ + $(C_TREE_H) $(C_COMMON_H) $(TREE_GIMPLE_H) diagnostic.h $(HASHTAB_H) \ output.h varray.h langhooks.h tree-mudflap.h $(TM_H) coretypes.h tree-pretty-print.o : tree-pretty-print.c $(CONFIG_H) $(SYSTEM_H) \ errors.h $(TREE_H) diagnostic.h real.h $(HASHTAB_H) $(TREE_FLOW_H) \ @@ -1850,14 +1850,14 @@ tree-ssa-dce.o : tree-ssa-dce.c $(CONFIG_H) system.h errors.h $(TREE_H) \ coretypes.h $(TREE_DUMP_H) tree-pass.h flags.h tree-ssa-ccp.o : tree-ssa-ccp.c $(CONFIG_H) system.h errors.h $(TREE_H) \ $(RTL_H) $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \ - $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H) \ + $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \ $(EXPR_H) tree-pass.h flags.h langhooks.h tree-sra.o : tree-sra.c $(CONFIG_H) system.h errors.h $(TREE_H) $(RTL_H) \ $(TM_P_H) $(TREE_FLOW_H) diagnostic.h tree-inline.h \ - $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_SIMPLE_H) \ + $(TIMEVAR_H) $(TM_H) coretypes.h $(TREE_DUMP_H) $(TREE_GIMPLE_H) \ langhooks.h tree-pass.h flags.h tree-complex.o : tree-complex.c $(CONFIG_H) system.h $(TREE_H) \ - $(TM_H) $(TREE_FLOW_H) $(TREE_SIMPLE_H) tree-iterator.h tree-pass.h \ + $(TM_H) $(TREE_FLOW_H) $(TREE_GIMPLE_H) tree-iterator.h tree-pass.h \ flags.h df.o : df.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ insn-config.h $(RECOG_H) function.h $(REGS_H) alloc-pool.h hard-reg-set.h \ diff --git a/gcc/c-decl.c b/gcc/c-decl.c index d0fc708ea05..8ca5b086ca2 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -51,7 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "c-pragma.h" #include "langhooks.h" #include "tree-mudflap.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "diagnostic.h" #include "tree-dump.h" #include "cgraph.h" diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c new file mode 100644 index 00000000000..49b3a671b75 --- /dev/null +++ b/gcc/c-gimplify.c @@ -0,0 +1,1102 @@ +/* Tree lowering pass. This pass gimplifies the tree representation built + by the C-based front ends. The structure of gimplified, or + language-independent, trees is dictated by the grammar described in this + file. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Lowering of expressions contributed by Sebastian Pop + Re-written to support lowering of whole function trees, documentation + and miscellaneous cleanups by Diego Novillo + +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 "tree.h" +#include "errors.h" +#include "varray.h" +#include "c-tree.h" +#include "c-common.h" +#include "tree-gimple.h" +#include "hard-reg-set.h" +#include "basic-block.h" +#include "tree-flow.h" +#include "tree-inline.h" +#include "diagnostic.h" +#include "langhooks.h" +#include "langhooks-def.h" +#include "flags.h" +#include "rtl.h" +#include "toplev.h" +#include "tree-dump.h" +#include "c-pretty-print.h" +#include "cgraph.h" + + +/* The gimplification pass converts the language-dependent trees + (ld-trees) emitted by the parser into language-independent trees + (li-trees) that are the target of SSA analysis and transformations. + + Language-independent trees are based on the SIMPLE intermediate + representation used in the McCAT compiler framework: + + "Designing the McCAT Compiler Based on a Family of Structured + Intermediate Representations," + L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan, + Proceedings of the 5th International Workshop on Languages and + Compilers for Parallel Computing, no. 757 in Lecture Notes in + Computer Science, New Haven, Connecticut, pp. 406-420, + Springer-Verlag, August 3-5, 1992. + + http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html + + Basically, we walk down gimplifying the nodes that we encounter. As we + walk back up, we check that they fit our constraints, and copy them + into temporaries if not. */ + +/* Local declarations. */ + +static enum gimplify_status gimplify_expr_stmt (tree *); +static enum gimplify_status gimplify_decl_stmt (tree *); +static enum gimplify_status gimplify_for_stmt (tree *, tree *); +static enum gimplify_status gimplify_while_stmt (tree *); +static enum gimplify_status gimplify_do_stmt (tree *); +static enum gimplify_status gimplify_if_stmt (tree *); +static enum gimplify_status gimplify_switch_stmt (tree *); +static enum gimplify_status gimplify_return_stmt (tree *); +static enum gimplify_status gimplify_stmt_expr (tree *); +static enum gimplify_status gimplify_compound_literal_expr (tree *); +#if defined ENABLE_CHECKING +static int is_last_stmt_of_scope (tree); +#endif +static enum gimplify_status gimplify_block (tree *, tree *); +static enum gimplify_status gimplify_cleanup (tree *, tree *); +static tree gimplify_c_loop (tree, tree, tree, bool); +static void push_context (void); +static void pop_context (void); +static tree c_build_bind_expr (tree, tree); +static void add_block_to_enclosing (tree); +static void gimplify_condition (tree *); + +enum bc_t { bc_break = 0, bc_continue = 1 }; +static tree begin_bc_block (enum bc_t); +static tree finish_bc_block (tree, tree); +static tree build_bc_goto (enum bc_t); + +static struct c_gimplify_ctx +{ + /* For handling break and continue. */ + tree current_bc_label; + tree bc_id[2]; +} *ctxp; + +static void +push_context (void) +{ + if (ctxp) + abort (); + ctxp = (struct c_gimplify_ctx *) xcalloc (1, sizeof (struct c_gimplify_ctx)); + ctxp->bc_id[bc_continue] = get_identifier ("continue"); + ctxp->bc_id[bc_break] = get_identifier ("break"); +} + +static void +pop_context (void) +{ + if (!ctxp || ctxp->current_bc_label) + abort (); + free (ctxp); + ctxp = NULL; +} + +/* Gimplification of statement trees. */ + +/* Convert the tree representation of FNDECL from C frontend trees to + GENERIC. */ + +void +c_genericize (tree fndecl) +{ + FILE *dump_file; + int local_dump_flags; + struct cgraph_node *cgn; + + /* Dump the C-specific tree IR. */ + dump_file = dump_begin (TDI_original, &local_dump_flags); + if (dump_file) + { + fprintf (dump_file, "\n;; Function %s", + (*lang_hooks.decl_printable_name) (fndecl, 2)); + fprintf (dump_file, " (%s)\n", + IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))); + fprintf (dump_file, ";; enabled by -%s\n", dump_flag_name (TDI_original)); + fprintf (dump_file, "\n"); + + if (local_dump_flags & TDF_RAW) + dump_node (DECL_SAVED_TREE (fndecl), + TDF_SLIM | local_dump_flags, dump_file); + else + print_c_tree (dump_file, DECL_SAVED_TREE (fndecl)); + fprintf (dump_file, "\n"); + + dump_end (TDI_original, dump_file); + } + + /* Go ahead and gimplify for now. */ + push_context (); + gimplify_function_tree (fndecl); + pop_context (); + + /* Dump the genericized tree IR. */ + dump_function (TDI_generic, fndecl); + + /* Genericize all nested functions now. We do things in this order so + that items like VLA sizes are expanded properly in the context of + the correct function. */ + cgn = cgraph_node (fndecl); + for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) + c_genericize (cgn->decl); +} + +/* Entry point for the tree lowering pass. Recursively scan + *STMT_P and convert it to a GIMPLE tree. */ + +int +c_gimplify_stmt (tree *stmt_p) +{ + tree stmt, next; + tree outer_pre = NULL_TREE; + + /* PRE and POST are tree chains that contain the side-effects of the + gimplified tree. For instance, given the expression tree: + + c = ++a * 3 + b++; + + After gimplification, the tree will be re-written as: + + a = a + 1; + t1 = a * 3; <-- PRE + c = t1 + b; + b = b + 1; <-- POST */ + + for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next) + { + tree pre, post; + int saved_stmts_are_full_exprs_p; + location_t stmt_locus; + enum gimplify_status ret; + + /* Set up context appropriately for handling this statement. */ + saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); + prep_stmt (stmt); + stmt_locus = input_location; + + pre = NULL_TREE; + post = NULL_TREE; + + next = TREE_CHAIN (stmt); + + switch (TREE_CODE (stmt)) + { + case COMPOUND_STMT: + stmt = COMPOUND_BODY (stmt); + ret = GS_OK; + break; + + case SCOPE_STMT: + ret = gimplify_block (&stmt, &next); + break; + + case FOR_STMT: + ret = gimplify_for_stmt (&stmt, &next); + break; + + case WHILE_STMT: + ret = gimplify_while_stmt (&stmt); + break; + + case DO_STMT: + ret = gimplify_do_stmt (&stmt); + break; + + case IF_STMT: + ret = gimplify_if_stmt (&stmt); + break; + + case SWITCH_STMT: + ret = gimplify_switch_stmt (&stmt); + break; + + case EXPR_STMT: + ret = gimplify_expr_stmt (&stmt); + break; + + case RETURN_STMT: + ret = gimplify_return_stmt (&stmt); + break; + + case DECL_STMT: + ret = gimplify_decl_stmt (&stmt); + break; + + case LABEL_STMT: + stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt)); + ret = GS_OK; + break; + + case GOTO_STMT: + stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt)); + ret = GS_OK; + break; + + case CASE_LABEL: + { + tree label = create_artificial_label (); + stmt = build (CASE_LABEL_EXPR, void_type_node, + CASE_LOW (stmt), CASE_HIGH (stmt), label); + ret = GS_OK; + } + break; + + case CONTINUE_STMT: + stmt = build_bc_goto (bc_continue); + ret = GS_OK; + break; + + case BREAK_STMT: + stmt = build_bc_goto (bc_break); + ret = GS_OK; + break; + + case CLEANUP_STMT: + ret = gimplify_cleanup (&stmt, &next); + break; + + case ASM_STMT: + { + tree new_stmt = build (ASM_EXPR, void_type_node, ASM_STRING (stmt), + ASM_OUTPUTS (stmt), ASM_INPUTS (stmt), + ASM_CLOBBERS (stmt)); + ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt); + ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt); + stmt = new_stmt; + ret = GS_OK; + } + break; + + default: + if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next)) + { + ret = GS_OK; + break; + } + + fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n"); + debug_tree (stmt); + abort (); + break; + } + + switch (ret) + { + case GS_ERROR: + goto cont; + case GS_OK: + gimplify_stmt (&stmt); + break; + case GS_ALL_DONE: + break; + default: + abort (); + } + + /* PRE and POST now contain a list of statements for all the + side-effects in STMT. */ + + append_to_statement_list (stmt, &pre); + append_to_statement_list (post, &pre); + annotate_all_with_locus (&pre, stmt_locus); + + append_to_statement_list (pre, &outer_pre); + cont: + /* Restore saved state. */ + current_stmt_tree ()->stmts_are_full_exprs_p + = saved_stmts_are_full_exprs_p; + } + append_to_statement_list (stmt, &outer_pre); + *stmt_p = outer_pre; + + return GS_ALL_DONE; +} + +static void +add_block_to_enclosing (tree block) +{ + tree enclosing; + + for (enclosing = gimple_current_bind_expr (); + enclosing; enclosing = TREE_CHAIN (enclosing)) + if (BIND_EXPR_BLOCK (enclosing)) + break; + + enclosing = BIND_EXPR_BLOCK (enclosing); + BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); +} + +/* Genericize a scope by creating a new BIND_EXPR. + BLOCK is either a BLOCK representing the scope or a chain of _DECLs. + In the latter case, we need to create a new BLOCK and add it to the + BLOCK_SUBBLOCKS of the enclosing block. + BODY is a chain of C _STMT nodes for the contents of the scope, to be + genericized. */ + +static tree +c_build_bind_expr (tree block, tree body) +{ + tree decls, bind; + + if (block == NULL_TREE) + decls = NULL_TREE; + else if (TREE_CODE (block) == BLOCK) + decls = BLOCK_VARS (block); + else + { + decls = block; + if (DECL_ARTIFICIAL (decls)) + block = NULL_TREE; + else + { + block = make_node (BLOCK); + BLOCK_VARS (block) = decls; + add_block_to_enclosing (block); + } + } + + if (!body) + body = build_empty_stmt (); + + bind = build (BIND_EXPR, void_type_node, decls, body, block); + TREE_SIDE_EFFECTS (bind) = 1; + + return bind; +} + +/* Genericize a syntactic block by removing the bracketing SCOPE_STMTs and + wrapping the intervening code in a BIND_EXPR. This function assumes + that matching SCOPE_STMTs will always appear in the same statement + sequence. */ + +static enum gimplify_status +gimplify_block (tree *stmt_p, tree *next_p) +{ + tree *p; + tree block; + tree bind; + int depth; + location_t stmt_locus; + + if (!SCOPE_BEGIN_P (*stmt_p)) + { + /* Can wind up mismatched with syntax errors. */ + if (!errorcount && !sorrycount) + abort (); + *stmt_p = NULL; + return GS_ERROR; + } + + block = SCOPE_STMT_BLOCK (*stmt_p); + + /* Find the matching ending SCOPE_STMT. */ + depth = 1; + for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p)) + { + if (*p == NULL) + break; + if (TREE_CODE (*p) == SCOPE_STMT) + { + if (SCOPE_BEGIN_P (*p)) + ++depth; + else if (--depth == 0) + break; + } + } + + stmt_locus = input_location; + if (*p) + { + if (SCOPE_STMT_BLOCK (*p) != block) + abort (); + if (EXPR_LOCUS (*p)) + stmt_locus = *EXPR_LOCUS (*p); + *next_p = TREE_CHAIN (*p); + *p = NULL_TREE; + } + else + { + /* Can wind up mismatched with syntax errors. */ + if (!errorcount && !sorrycount) + abort (); + } + + bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p)); + *stmt_p = bind; + input_location = stmt_locus; + + return GS_OK; +} + +/* Genericize a CLEANUP_STMT. Just wrap everything from here to the end of + the block in a TRY_FINALLY_EXPR. Or a TRY_CATCH_EXPR, if it's an + EH-only cleanup. */ + +static enum gimplify_status +gimplify_cleanup (tree *stmt_p, tree *next_p) +{ + tree stmt = *stmt_p; + tree body = TREE_CHAIN (stmt); + tree cleanup = CLEANUP_EXPR (stmt); + enum tree_code code + = (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR); + + if (!body) + body = build_empty_stmt (); + if (!cleanup) + cleanup = build_empty_stmt (); + + *stmt_p = build (code, void_type_node, body, cleanup); + *next_p = NULL_TREE; + + return GS_OK; +} + +/* Gimplify an EXPR_STMT node. + + STMT is the statement node. + + PRE_P points to the list where side effects that must happen before + STMT should be stored. + + POST_P points to the list where side effects that must happen after + STMT should be stored. */ + +static enum gimplify_status +gimplify_expr_stmt (tree *stmt_p) +{ + tree stmt = EXPR_STMT_EXPR (*stmt_p); + + if (stmt == error_mark_node) + stmt = NULL; + + /* Gimplification of a statement expression will nullify the + statement if all its side effects are moved to *PRE_P and *POST_P. + + In this case we will not want to emit the gimplified statement. + However, we may still want to emit a warning, so we do that before + gimplification. */ + if (stmt && (extra_warnings || warn_unused_value)) + { + if (!TREE_SIDE_EFFECTS (stmt)) + { + if (!IS_EMPTY_STMT (stmt) + && !VOID_TYPE_P (TREE_TYPE (stmt)) + && !TREE_NO_WARNING (stmt)) + warning ("statement with no effect"); + } + else if (warn_unused_value) + { + /* Kludge for 20020220-2.c. warn_if_unused_value shouldn't use + the stmt file location info. */ + set_file_and_line_for_stmt (input_location); + warn_if_unused_value (stmt); + } + } + + if (stmt == NULL_TREE) + stmt = build_empty_stmt (); + else if (stmts_are_full_exprs_p ()) + stmt = build1 (CLEANUP_POINT_EXPR, void_type_node, stmt); + + *stmt_p = stmt; + + return GS_OK; +} + +/* If the condition for a loop (or the like) is a decl, it will be a + TREE_LIST where the TREE_PURPOSE is a DECL_STMT and the TREE_VALUE is + a use of the decl. Turn such a thing into a COMPOUND_EXPR. */ + +static void +gimplify_condition (tree *cond_p) +{ + tree cond = *cond_p; + if (cond && TREE_CODE (cond) == TREE_LIST) + { + tree decl = TREE_PURPOSE (cond); + tree value = TREE_VALUE (cond); + c_gimplify_stmt (&decl); + *cond_p = build (COMPOUND_EXPR, TREE_TYPE (value), decl, value); + } +} + +/* Begin a scope which can be exited by a break or continue statement. BC + indicates which. + + Just creates a label and pushes it into the current context. */ + +static tree +begin_bc_block (enum bc_t bc) +{ + tree label = create_artificial_label (); + DECL_NAME (label) = ctxp->bc_id[bc]; + TREE_CHAIN (label) = ctxp->current_bc_label; + ctxp->current_bc_label = label; + return label; +} + +/* Finish a scope which can be exited by a break or continue statement. + LABEL was returned from the most recent call to begin_bc_block. BODY is + an expression for the contents of the scope. + + If we saw a break (or continue) in the scope, append a LABEL_EXPR to + body. Otherwise, just forget the label. */ + +static tree +finish_bc_block (tree label, tree body) +{ + if (label != ctxp->current_bc_label) + abort (); + + if (TREE_USED (label)) + { + tree t, sl = NULL; + + /* Clear the name so flow can delete the label. */ + DECL_NAME (label) = NULL_TREE; + t = build1 (LABEL_EXPR, void_type_node, label); + + append_to_statement_list (body, &sl); + append_to_statement_list (t, &sl); + body = sl; + } + + ctxp->current_bc_label = TREE_CHAIN (label); + TREE_CHAIN (label) = NULL_TREE; + return body; +} + +/* Build a GOTO_EXPR to represent a break or continue statement. BC + indicates which. */ + +static tree +build_bc_goto (enum bc_t bc) +{ + tree label; + tree target_name = ctxp->bc_id[bc]; + + /* Look for the appropriate type of label. */ + for (label = ctxp->current_bc_label; + label; + label = TREE_CHAIN (label)) + if (DECL_NAME (label) == target_name) + break; + + if (label == NULL_TREE) + { + if (bc == bc_break) + error ("break statement not within loop or switch"); + else + error ("continue statement not within loop or switch"); + + return NULL_TREE; + } + + /* Mark the label used for finish_bc_block. */ + TREE_USED (label) = 1; + return build1 (GOTO_EXPR, void_type_node, label); +} + +/* Build a generic representation of one of the C loop forms. COND is the + loop condition or NULL_TREE. BODY is the (possibly compound) statement + controlled by the loop. INCR is the increment expression of a for-loop, + or NULL_TREE. COND_IS_FIRST indicates whether the condition is + evaluated before the loop body as in while and for loops, or after the + loop body as in do-while loops. */ + +static tree +gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) +{ + tree top, entry, exit, cont_block, break_block, stmt_list, t; + location_t stmt_locus; + + stmt_locus = input_location; + + /* Detect do { ... } while (0) and don't generate loop construct. */ + if (!cond_is_first && cond && integer_zerop (cond)) + top = cond = NULL; + else + { + /* If we use a LOOP_EXPR here, we have to feed the whole thing + back through the main gimplifier to lower it. Given that we + have to gimplify the loop body NOW so that we can resolve + break/continue stmts, seems easier to just expand to gotos. */ + top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + } + + break_block = begin_bc_block (bc_break); + + if (top) + { + /* If we have an exit condition, then we build an IF with gotos either + out of the loop, or to the top of it. If there's no exit condition, + then we just build a jump back to the top. */ + exit = build_and_jump (&LABEL_EXPR_LABEL (top)); + if (cond) + { + gimplify_condition (&cond); + t = build_bc_goto (bc_break); + exit = build (COND_EXPR, void_type_node, cond, exit, t); + exit = fold (exit); + gimplify_stmt (&exit); + } + } + else + exit = NULL_TREE; + + cont_block = begin_bc_block (bc_continue); + + gimplify_stmt (&body); + if (incr && stmts_are_full_exprs_p ()) + incr = fold (build1 (CLEANUP_POINT_EXPR, void_type_node, incr)); + gimplify_stmt (&incr); + + body = finish_bc_block (cont_block, body); + + stmt_list = NULL; + + if (cond_is_first && cond) + { + entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); + t = build_and_jump (&LABEL_EXPR_LABEL (entry)); + append_to_statement_list (t, &stmt_list); + } + else + entry = NULL_TREE; + + append_to_statement_list (top, &stmt_list); + append_to_statement_list (body, &stmt_list); + append_to_statement_list (incr, &stmt_list); + append_to_statement_list (entry, &stmt_list); + append_to_statement_list (exit, &stmt_list); + + annotate_all_with_locus (&stmt_list, stmt_locus); + + return finish_bc_block (break_block, stmt_list); +} + +/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the + prequeue and hand off to gimplify_c_loop. */ + +static enum gimplify_status +gimplify_for_stmt (tree *stmt_p, tree *next_p) +{ + tree stmt = *stmt_p; + tree init = FOR_INIT_STMT (stmt); + + if (init) + { + /* Reorganize the statements so that we do the right thing with a + CLEANUP_STMT. We want the FOR_STMT and nothing else to be in the + scope of the cleanup, so play with pointers to accomplish that. */ + FOR_INIT_STMT (stmt) = NULL_TREE; + chainon (init, stmt); + *stmt_p = init; + *next_p = TREE_CHAIN (stmt); + TREE_CHAIN (stmt) = NULL_TREE; + c_gimplify_stmt (stmt_p); + } + else + *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt), + FOR_EXPR (stmt), 1); + + return GS_ALL_DONE; +} + +/* Gimplify a WHILE_STMT node. */ + +static enum gimplify_status +gimplify_while_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + *stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt), + NULL_TREE, 1); + return GS_ALL_DONE; +} + +/* Gimplify a DO_STMT node. */ + +static enum gimplify_status +gimplify_do_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + *stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt), + NULL_TREE, 0); + return GS_ALL_DONE; +} + +/* Genericize an IF_STMT by turning it into a COND_EXPR. */ + +static enum gimplify_status +gimplify_if_stmt (tree *stmt_p) +{ + tree stmt, then_, else_; + + stmt = *stmt_p; + restart: + then_ = THEN_CLAUSE (stmt); + else_ = ELSE_CLAUSE (stmt); + + if (!then_) + then_ = build_empty_stmt (); + if (!else_) + else_ = build_empty_stmt (); + + stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_); + gimplify_condition (& TREE_OPERAND (stmt, 0)); + *stmt_p = stmt; + + /* Handle properly nested if-else chains via iteration instead of + mutual recursion between gimplify.c and c-simplify.c. */ + annotate_with_locus (stmt, input_location); + if (TREE_CODE (else_) == IF_STMT && !TREE_CHAIN (else_)) + { + stmt_p = &COND_EXPR_ELSE (stmt); + stmt = else_; + prep_stmt (stmt); + goto restart; + } + + return GS_OK; +} + +/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ + +static enum gimplify_status +gimplify_switch_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + tree break_block, body; + location_t stmt_locus = input_location; + + break_block = begin_bc_block (bc_break); + + gimplify_condition (&SWITCH_COND (stmt)); + + body = SWITCH_BODY (stmt); + if (!body) + body = build_empty_stmt (); + + *stmt_p = build (SWITCH_EXPR, SWITCH_TYPE (stmt), SWITCH_COND (stmt), + body, NULL_TREE); + annotate_with_locus (*stmt_p, stmt_locus); + gimplify_stmt (stmt_p); + + *stmt_p = finish_bc_block (break_block, *stmt_p); + return GS_ALL_DONE; +} + +/* Genericize a RETURN_STMT by turning it into a RETURN_EXPR. */ + +static enum gimplify_status +gimplify_return_stmt (tree *stmt_p) +{ + tree expr = RETURN_STMT_EXPR (*stmt_p); + expr = build1 (RETURN_EXPR, void_type_node, expr); + if (stmts_are_full_exprs_p ()) + expr = build1 (CLEANUP_POINT_EXPR, void_type_node, expr); + *stmt_p = expr; + return GS_OK; +} + +/* Gimplifies a DECL_STMT node T. + + If a declaration V has an initial value I, create an expression 'V = I' + and insert it after the DECL_STMT. + + PRE_P is a queue for effects that should happen before the DECL_STMT. + + MID_P is a queue for effects that should happen after the DECL_STMT, + but before uses of the initialized decl. + + POST_P is a queue for effects that should happen after uses of the + initialized decl. + + Usually these last two will be the same, but they may need to be + different if the DECL_STMT is somehow embedded in an expression. */ + +static enum gimplify_status +gimplify_decl_stmt (tree *stmt_p) +{ + tree stmt = *stmt_p; + tree decl = DECL_STMT_DECL (stmt); + tree pre = NULL_TREE; + tree post = NULL_TREE; + + if (TREE_TYPE (decl) == error_mark_node) + { + *stmt_p = NULL; + return GS_ERROR; + } + + if (TREE_CODE (decl) == TYPE_DECL) + { + tree type = TREE_TYPE (decl); + if (TYPE_SIZE_UNIT (type) + && !TREE_CONSTANT (TYPE_SIZE_UNIT (type))) + { + /* This is a variable-sized array type. Simplify its size. */ + tree temp = TYPE_SIZE_UNIT (type); + gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue); + } + } + + if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) + { + tree init = DECL_INITIAL (decl); + + if (!TREE_CONSTANT (DECL_SIZE (decl))) + { + tree pt_type = build_pointer_type (TREE_TYPE (decl)); + tree alloc, size; + + /* This is a variable-sized decl. Simplify its size and mark it + for deferred expansion. Note that mudflap depends on the format + of the emitted code: see mx_register_decls(). */ + + size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post); + DECL_DEFER_OUTPUT (decl) = 1; + alloc = build_function_call_expr + (implicit_built_in_decls[BUILT_IN_STACK_ALLOC], + tree_cons (NULL_TREE, + build1 (ADDR_EXPR, pt_type, decl), + tree_cons (NULL_TREE, size, NULL_TREE))); + append_to_compound_expr (alloc, &pre); + } + + if (init && init != error_mark_node) + { + if (!TREE_STATIC (decl)) + { + /* Do not warn about int x = x; as it is a GCC extension + to turn off this warning but only if warn_init_self + is zero. */ + if (init == decl && !warn_init_self) + TREE_NO_WARNING (decl) = 1; + + DECL_INITIAL (decl) = NULL_TREE; + init = build (MODIFY_EXPR, void_type_node, decl, init); + if (stmts_are_full_exprs_p ()) + init = build1 (CLEANUP_POINT_EXPR, void_type_node, init); + append_to_compound_expr (init, &pre); + } + else + { + /* We must still examine initializers for static variables + as they may contain a label address. */ + walk_tree (&init, force_labels_r, NULL, NULL); + } + } + + /* This decl isn't mentioned in the enclosing block, so add it to the + list of temps. FIXME it seems a bit of a kludge to say that + anonymous artificial vars aren't pushed, but everything else is. */ + if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE) + gimple_add_tmp_var (decl); + } + + append_to_compound_expr (post, &pre); + *stmt_p = pre; + return GS_OK; +} + +/* Gimplification of expression trees. */ + +/* Gimplify a C99 compound literal expression. This just means adding the + DECL_STMT before the current EXPR_STMT and using its anonymous decl + instead. */ + +static enum gimplify_status +gimplify_compound_literal_expr (tree *expr_p) +{ + tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p); + tree decl = DECL_STMT_DECL (decl_s); + + /* This decl isn't mentioned in the enclosing block, so add it to the + list of temps. FIXME it seems a bit of a kludge to say that + anonymous artificial vars aren't pushed, but everything else is. */ + if (DECL_NAME (decl) == NULL_TREE) + gimple_add_tmp_var (decl); + + gimplify_decl_stmt (&decl_s); + *expr_p = decl_s ? decl_s : decl; + return GS_OK; +} + +/* Do C-specific gimplification. Args are as for gimplify_expr. */ + +int +c_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, + tree *post_p ATTRIBUTE_UNUSED) +{ + enum tree_code code = TREE_CODE (*expr_p); + + if (STATEMENT_CODE_P (code)) + return c_gimplify_stmt (expr_p); + + switch (code) + { + case COMPOUND_LITERAL_EXPR: + return gimplify_compound_literal_expr (expr_p); + + case STMT_EXPR: + return gimplify_stmt_expr (expr_p); + + default: + return GS_UNHANDLED; + } +} + +/* Returns the final EXPR_STMT which represents the return value of a + STMT_EXPR, or NULL_TREE if none. */ + +tree +stmt_expr_last_stmt (tree stmt_expr) +{ + tree body = STMT_EXPR_STMT (stmt_expr); + tree last_stmt, substmt; + + /* Splice the last expression out of the STMT chain. */ + last_stmt = NULL_TREE; + for (substmt = COMPOUND_BODY (body); substmt; + substmt = TREE_CHAIN (substmt)) + if (TREE_CODE (substmt) != SCOPE_STMT) + last_stmt = substmt; + + if (last_stmt == NULL_TREE + || TREE_CODE (last_stmt) != EXPR_STMT + || (TREE_TYPE (last_stmt) + && VOID_TYPE_P (TREE_TYPE (last_stmt)))) + { + location_t loc; + if (last_stmt && EXPR_LOCUS (last_stmt)) + loc = *EXPR_LOCUS (last_stmt); + else if (EXPR_LOCUS (stmt_expr)) + loc = *EXPR_LOCUS (stmt_expr); + else + loc = input_location; + warning ("%Hstatement-expressions should end with a " + "non-void expression", &loc); + last_stmt = NULL_TREE; + } + +#if defined ENABLE_CHECKING + if (last_stmt && !is_last_stmt_of_scope (last_stmt)) + abort (); +#endif + + return last_stmt; +} + +/* Gimplify a STMT_EXPR. EXPR_P points to the expression to gimplify. + After gimplification, if the STMT_EXPR returns a value, EXPR_P will + point to a new temporary that holds that value; otherwise it will be + null. + + PRE_P points to the list where side effects that must happen before + *EXPR_P should be stored. */ + +static enum gimplify_status +gimplify_stmt_expr (tree *expr_p) +{ + tree body = STMT_EXPR_STMT (*expr_p); + + if (VOID_TYPE_P (TREE_TYPE (*expr_p))) + { + *expr_p = body; + return c_gimplify_stmt (expr_p); + } + else + { + tree last_stmt = stmt_expr_last_stmt (*expr_p); + tree last_expr = NULL_TREE; + + if (last_stmt) + { + last_expr = EXPR_STMT_EXPR (last_stmt); + + if (stmts_are_full_exprs_p ()) + last_expr = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (last_expr), + last_expr); + EXPR_STMT_EXPR (last_stmt) = NULL_TREE; + } + + /* Genericize the block. */ + c_gimplify_stmt (&body); + + /* Now retrofit that last expression into the BIND_EXPR. */ + if (last_expr) + { + tree *sub_p; + + if (!STMT_EXPR_NO_SCOPE (*expr_p)) + { + /* Our BIND_EXPR will always be hidden within + a STATEMENT_LIST. Discard that. */ + body = expr_first (body); + sub_p = &BIND_EXPR_BODY (body); + + /* Append the last expression to the end of the BIND_EXPR. + We'll now re-process this, and let voidify_wrapper_expr + do its job. */ + append_to_statement_list_force (last_expr, sub_p); + TREE_TYPE (body) = TREE_TYPE (last_expr); + } + else + append_to_compound_expr (last_expr, &body); + } + + *expr_p = body; + return GS_OK; + } +} + +/* Code generation. */ + +/* Miscellaneous helpers. */ + +#if defined ENABLE_CHECKING +/* Return nonzero if STMT is the last statement of its scope. */ + +static int +is_last_stmt_of_scope (tree stmt) +{ + return (TREE_CHAIN (stmt) == NULL_TREE + || (TREE_CODE (TREE_CHAIN (stmt)) == SCOPE_STMT + && SCOPE_END_P (TREE_CHAIN (stmt)))); +} +#endif diff --git a/gcc/c-simplify.c b/gcc/c-simplify.c deleted file mode 100644 index bd50b5e025b..00000000000 --- a/gcc/c-simplify.c +++ /dev/null @@ -1,1102 +0,0 @@ -/* Tree lowering pass. This pass gimplifies the tree representation built - by the C-based front ends. The structure of gimplified, or - language-independent, trees is dictated by the grammar described in this - file. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. - Lowering of expressions contributed by Sebastian Pop - Re-written to support lowering of whole function trees, documentation - and miscellaneous cleanups by Diego Novillo - -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 "tree.h" -#include "errors.h" -#include "varray.h" -#include "c-tree.h" -#include "c-common.h" -#include "tree-simple.h" -#include "hard-reg-set.h" -#include "basic-block.h" -#include "tree-flow.h" -#include "tree-inline.h" -#include "diagnostic.h" -#include "langhooks.h" -#include "langhooks-def.h" -#include "flags.h" -#include "rtl.h" -#include "toplev.h" -#include "tree-dump.h" -#include "c-pretty-print.h" -#include "cgraph.h" - - -/* The gimplification pass converts the language-dependent trees - (ld-trees) emitted by the parser into language-independent trees - (li-trees) that are the target of SSA analysis and transformations. - - Language-independent trees are based on the SIMPLE intermediate - representation used in the McCAT compiler framework: - - "Designing the McCAT Compiler Based on a Family of Structured - Intermediate Representations," - L. Hendren, C. Donawa, M. Emami, G. Gao, Justiani, and B. Sridharan, - Proceedings of the 5th International Workshop on Languages and - Compilers for Parallel Computing, no. 757 in Lecture Notes in - Computer Science, New Haven, Connecticut, pp. 406-420, - Springer-Verlag, August 3-5, 1992. - - http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html - - Basically, we walk down gimplifying the nodes that we encounter. As we - walk back up, we check that they fit our constraints, and copy them - into temporaries if not. */ - -/* Local declarations. */ - -static enum gimplify_status gimplify_expr_stmt (tree *); -static enum gimplify_status gimplify_decl_stmt (tree *); -static enum gimplify_status gimplify_for_stmt (tree *, tree *); -static enum gimplify_status gimplify_while_stmt (tree *); -static enum gimplify_status gimplify_do_stmt (tree *); -static enum gimplify_status gimplify_if_stmt (tree *); -static enum gimplify_status gimplify_switch_stmt (tree *); -static enum gimplify_status gimplify_return_stmt (tree *); -static enum gimplify_status gimplify_stmt_expr (tree *); -static enum gimplify_status gimplify_compound_literal_expr (tree *); -#if defined ENABLE_CHECKING -static int is_last_stmt_of_scope (tree); -#endif -static enum gimplify_status gimplify_block (tree *, tree *); -static enum gimplify_status gimplify_cleanup (tree *, tree *); -static tree gimplify_c_loop (tree, tree, tree, bool); -static void push_context (void); -static void pop_context (void); -static tree c_build_bind_expr (tree, tree); -static void add_block_to_enclosing (tree); -static void gimplify_condition (tree *); - -enum bc_t { bc_break = 0, bc_continue = 1 }; -static tree begin_bc_block (enum bc_t); -static tree finish_bc_block (tree, tree); -static tree build_bc_goto (enum bc_t); - -static struct c_gimplify_ctx -{ - /* For handling break and continue. */ - tree current_bc_label; - tree bc_id[2]; -} *ctxp; - -static void -push_context (void) -{ - if (ctxp) - abort (); - ctxp = (struct c_gimplify_ctx *) xcalloc (1, sizeof (struct c_gimplify_ctx)); - ctxp->bc_id[bc_continue] = get_identifier ("continue"); - ctxp->bc_id[bc_break] = get_identifier ("break"); -} - -static void -pop_context (void) -{ - if (!ctxp || ctxp->current_bc_label) - abort (); - free (ctxp); - ctxp = NULL; -} - -/* Gimplification of statement trees. */ - -/* Convert the tree representation of FNDECL from C frontend trees to - GENERIC. */ - -void -c_genericize (tree fndecl) -{ - FILE *dump_file; - int local_dump_flags; - struct cgraph_node *cgn; - - /* Dump the C-specific tree IR. */ - dump_file = dump_begin (TDI_original, &local_dump_flags); - if (dump_file) - { - fprintf (dump_file, "\n;; Function %s", - (*lang_hooks.decl_printable_name) (fndecl, 2)); - fprintf (dump_file, " (%s)\n", - IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl))); - fprintf (dump_file, ";; enabled by -%s\n", dump_flag_name (TDI_original)); - fprintf (dump_file, "\n"); - - if (local_dump_flags & TDF_RAW) - dump_node (DECL_SAVED_TREE (fndecl), - TDF_SLIM | local_dump_flags, dump_file); - else - print_c_tree (dump_file, DECL_SAVED_TREE (fndecl)); - fprintf (dump_file, "\n"); - - dump_end (TDI_original, dump_file); - } - - /* Go ahead and gimplify for now. */ - push_context (); - gimplify_function_tree (fndecl); - pop_context (); - - /* Dump the genericized tree IR. */ - dump_function (TDI_generic, fndecl); - - /* Genericize all nested functions now. We do things in this order so - that items like VLA sizes are expanded properly in the context of - the correct function. */ - cgn = cgraph_node (fndecl); - for (cgn = cgn->nested; cgn ; cgn = cgn->next_nested) - c_genericize (cgn->decl); -} - -/* Entry point for the tree lowering pass. Recursively scan - *STMT_P and convert it to a GIMPLE tree. */ - -int -c_gimplify_stmt (tree *stmt_p) -{ - tree stmt, next; - tree outer_pre = NULL_TREE; - - /* PRE and POST are tree chains that contain the side-effects of the - gimplified tree. For instance, given the expression tree: - - c = ++a * 3 + b++; - - After gimplification, the tree will be re-written as: - - a = a + 1; - t1 = a * 3; <-- PRE - c = t1 + b; - b = b + 1; <-- POST */ - - for (stmt = *stmt_p; stmt && stmt != error_mark_node; stmt = next) - { - tree pre, post; - int saved_stmts_are_full_exprs_p; - location_t stmt_locus; - enum gimplify_status ret; - - /* Set up context appropriately for handling this statement. */ - saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p (); - prep_stmt (stmt); - stmt_locus = input_location; - - pre = NULL_TREE; - post = NULL_TREE; - - next = TREE_CHAIN (stmt); - - switch (TREE_CODE (stmt)) - { - case COMPOUND_STMT: - stmt = COMPOUND_BODY (stmt); - ret = GS_OK; - break; - - case SCOPE_STMT: - ret = gimplify_block (&stmt, &next); - break; - - case FOR_STMT: - ret = gimplify_for_stmt (&stmt, &next); - break; - - case WHILE_STMT: - ret = gimplify_while_stmt (&stmt); - break; - - case DO_STMT: - ret = gimplify_do_stmt (&stmt); - break; - - case IF_STMT: - ret = gimplify_if_stmt (&stmt); - break; - - case SWITCH_STMT: - ret = gimplify_switch_stmt (&stmt); - break; - - case EXPR_STMT: - ret = gimplify_expr_stmt (&stmt); - break; - - case RETURN_STMT: - ret = gimplify_return_stmt (&stmt); - break; - - case DECL_STMT: - ret = gimplify_decl_stmt (&stmt); - break; - - case LABEL_STMT: - stmt = build1 (LABEL_EXPR, void_type_node, LABEL_STMT_LABEL (stmt)); - ret = GS_OK; - break; - - case GOTO_STMT: - stmt = build1 (GOTO_EXPR, void_type_node, GOTO_DESTINATION (stmt)); - ret = GS_OK; - break; - - case CASE_LABEL: - { - tree label = create_artificial_label (); - stmt = build (CASE_LABEL_EXPR, void_type_node, - CASE_LOW (stmt), CASE_HIGH (stmt), label); - ret = GS_OK; - } - break; - - case CONTINUE_STMT: - stmt = build_bc_goto (bc_continue); - ret = GS_OK; - break; - - case BREAK_STMT: - stmt = build_bc_goto (bc_break); - ret = GS_OK; - break; - - case CLEANUP_STMT: - ret = gimplify_cleanup (&stmt, &next); - break; - - case ASM_STMT: - { - tree new_stmt = build (ASM_EXPR, void_type_node, ASM_STRING (stmt), - ASM_OUTPUTS (stmt), ASM_INPUTS (stmt), - ASM_CLOBBERS (stmt)); - ASM_INPUT_P (new_stmt) = ASM_INPUT_P (stmt); - ASM_VOLATILE_P (new_stmt) = ASM_VOLATILE_P (stmt); - stmt = new_stmt; - ret = GS_OK; - } - break; - - default: - if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt, &next)) - { - ret = GS_OK; - break; - } - - fprintf (stderr, "unhandled statement node in c_gimplify_stmt:\n"); - debug_tree (stmt); - abort (); - break; - } - - switch (ret) - { - case GS_ERROR: - goto cont; - case GS_OK: - gimplify_stmt (&stmt); - break; - case GS_ALL_DONE: - break; - default: - abort (); - } - - /* PRE and POST now contain a list of statements for all the - side-effects in STMT. */ - - append_to_statement_list (stmt, &pre); - append_to_statement_list (post, &pre); - annotate_all_with_locus (&pre, stmt_locus); - - append_to_statement_list (pre, &outer_pre); - cont: - /* Restore saved state. */ - current_stmt_tree ()->stmts_are_full_exprs_p - = saved_stmts_are_full_exprs_p; - } - append_to_statement_list (stmt, &outer_pre); - *stmt_p = outer_pre; - - return GS_ALL_DONE; -} - -static void -add_block_to_enclosing (tree block) -{ - tree enclosing; - - for (enclosing = gimple_current_bind_expr (); - enclosing; enclosing = TREE_CHAIN (enclosing)) - if (BIND_EXPR_BLOCK (enclosing)) - break; - - enclosing = BIND_EXPR_BLOCK (enclosing); - BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); -} - -/* Genericize a scope by creating a new BIND_EXPR. - BLOCK is either a BLOCK representing the scope or a chain of _DECLs. - In the latter case, we need to create a new BLOCK and add it to the - BLOCK_SUBBLOCKS of the enclosing block. - BODY is a chain of C _STMT nodes for the contents of the scope, to be - genericized. */ - -static tree -c_build_bind_expr (tree block, tree body) -{ - tree decls, bind; - - if (block == NULL_TREE) - decls = NULL_TREE; - else if (TREE_CODE (block) == BLOCK) - decls = BLOCK_VARS (block); - else - { - decls = block; - if (DECL_ARTIFICIAL (decls)) - block = NULL_TREE; - else - { - block = make_node (BLOCK); - BLOCK_VARS (block) = decls; - add_block_to_enclosing (block); - } - } - - if (!body) - body = build_empty_stmt (); - - bind = build (BIND_EXPR, void_type_node, decls, body, block); - TREE_SIDE_EFFECTS (bind) = 1; - - return bind; -} - -/* Genericize a syntactic block by removing the bracketing SCOPE_STMTs and - wrapping the intervening code in a BIND_EXPR. This function assumes - that matching SCOPE_STMTs will always appear in the same statement - sequence. */ - -static enum gimplify_status -gimplify_block (tree *stmt_p, tree *next_p) -{ - tree *p; - tree block; - tree bind; - int depth; - location_t stmt_locus; - - if (!SCOPE_BEGIN_P (*stmt_p)) - { - /* Can wind up mismatched with syntax errors. */ - if (!errorcount && !sorrycount) - abort (); - *stmt_p = NULL; - return GS_ERROR; - } - - block = SCOPE_STMT_BLOCK (*stmt_p); - - /* Find the matching ending SCOPE_STMT. */ - depth = 1; - for (p = &TREE_CHAIN (*stmt_p);; p = &TREE_CHAIN (*p)) - { - if (*p == NULL) - break; - if (TREE_CODE (*p) == SCOPE_STMT) - { - if (SCOPE_BEGIN_P (*p)) - ++depth; - else if (--depth == 0) - break; - } - } - - stmt_locus = input_location; - if (*p) - { - if (SCOPE_STMT_BLOCK (*p) != block) - abort (); - if (EXPR_LOCUS (*p)) - stmt_locus = *EXPR_LOCUS (*p); - *next_p = TREE_CHAIN (*p); - *p = NULL_TREE; - } - else - { - /* Can wind up mismatched with syntax errors. */ - if (!errorcount && !sorrycount) - abort (); - } - - bind = c_build_bind_expr (block, TREE_CHAIN (*stmt_p)); - *stmt_p = bind; - input_location = stmt_locus; - - return GS_OK; -} - -/* Genericize a CLEANUP_STMT. Just wrap everything from here to the end of - the block in a TRY_FINALLY_EXPR. Or a TRY_CATCH_EXPR, if it's an - EH-only cleanup. */ - -static enum gimplify_status -gimplify_cleanup (tree *stmt_p, tree *next_p) -{ - tree stmt = *stmt_p; - tree body = TREE_CHAIN (stmt); - tree cleanup = CLEANUP_EXPR (stmt); - enum tree_code code - = (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR); - - if (!body) - body = build_empty_stmt (); - if (!cleanup) - cleanup = build_empty_stmt (); - - *stmt_p = build (code, void_type_node, body, cleanup); - *next_p = NULL_TREE; - - return GS_OK; -} - -/* Gimplify an EXPR_STMT node. - - STMT is the statement node. - - PRE_P points to the list where side effects that must happen before - STMT should be stored. - - POST_P points to the list where side effects that must happen after - STMT should be stored. */ - -static enum gimplify_status -gimplify_expr_stmt (tree *stmt_p) -{ - tree stmt = EXPR_STMT_EXPR (*stmt_p); - - if (stmt == error_mark_node) - stmt = NULL; - - /* Gimplification of a statement expression will nullify the - statement if all its side effects are moved to *PRE_P and *POST_P. - - In this case we will not want to emit the gimplified statement. - However, we may still want to emit a warning, so we do that before - gimplification. */ - if (stmt && (extra_warnings || warn_unused_value)) - { - if (!TREE_SIDE_EFFECTS (stmt)) - { - if (!IS_EMPTY_STMT (stmt) - && !VOID_TYPE_P (TREE_TYPE (stmt)) - && !TREE_NO_WARNING (stmt)) - warning ("statement with no effect"); - } - else if (warn_unused_value) - { - /* Kludge for 20020220-2.c. warn_if_unused_value shouldn't use - the stmt file location info. */ - set_file_and_line_for_stmt (input_location); - warn_if_unused_value (stmt); - } - } - - if (stmt == NULL_TREE) - stmt = build_empty_stmt (); - else if (stmts_are_full_exprs_p ()) - stmt = build1 (CLEANUP_POINT_EXPR, void_type_node, stmt); - - *stmt_p = stmt; - - return GS_OK; -} - -/* If the condition for a loop (or the like) is a decl, it will be a - TREE_LIST where the TREE_PURPOSE is a DECL_STMT and the TREE_VALUE is - a use of the decl. Turn such a thing into a COMPOUND_EXPR. */ - -static void -gimplify_condition (tree *cond_p) -{ - tree cond = *cond_p; - if (cond && TREE_CODE (cond) == TREE_LIST) - { - tree decl = TREE_PURPOSE (cond); - tree value = TREE_VALUE (cond); - c_gimplify_stmt (&decl); - *cond_p = build (COMPOUND_EXPR, TREE_TYPE (value), decl, value); - } -} - -/* Begin a scope which can be exited by a break or continue statement. BC - indicates which. - - Just creates a label and pushes it into the current context. */ - -static tree -begin_bc_block (enum bc_t bc) -{ - tree label = create_artificial_label (); - DECL_NAME (label) = ctxp->bc_id[bc]; - TREE_CHAIN (label) = ctxp->current_bc_label; - ctxp->current_bc_label = label; - return label; -} - -/* Finish a scope which can be exited by a break or continue statement. - LABEL was returned from the most recent call to begin_bc_block. BODY is - an expression for the contents of the scope. - - If we saw a break (or continue) in the scope, append a LABEL_EXPR to - body. Otherwise, just forget the label. */ - -static tree -finish_bc_block (tree label, tree body) -{ - if (label != ctxp->current_bc_label) - abort (); - - if (TREE_USED (label)) - { - tree t, sl = NULL; - - /* Clear the name so flow can delete the label. */ - DECL_NAME (label) = NULL_TREE; - t = build1 (LABEL_EXPR, void_type_node, label); - - append_to_statement_list (body, &sl); - append_to_statement_list (t, &sl); - body = sl; - } - - ctxp->current_bc_label = TREE_CHAIN (label); - TREE_CHAIN (label) = NULL_TREE; - return body; -} - -/* Build a GOTO_EXPR to represent a break or continue statement. BC - indicates which. */ - -static tree -build_bc_goto (enum bc_t bc) -{ - tree label; - tree target_name = ctxp->bc_id[bc]; - - /* Look for the appropriate type of label. */ - for (label = ctxp->current_bc_label; - label; - label = TREE_CHAIN (label)) - if (DECL_NAME (label) == target_name) - break; - - if (label == NULL_TREE) - { - if (bc == bc_break) - error ("break statement not within loop or switch"); - else - error ("continue statement not within loop or switch"); - - return NULL_TREE; - } - - /* Mark the label used for finish_bc_block. */ - TREE_USED (label) = 1; - return build1 (GOTO_EXPR, void_type_node, label); -} - -/* Build a generic representation of one of the C loop forms. COND is the - loop condition or NULL_TREE. BODY is the (possibly compound) statement - controlled by the loop. INCR is the increment expression of a for-loop, - or NULL_TREE. COND_IS_FIRST indicates whether the condition is - evaluated before the loop body as in while and for loops, or after the - loop body as in do-while loops. */ - -static tree -gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) -{ - tree top, entry, exit, cont_block, break_block, stmt_list, t; - location_t stmt_locus; - - stmt_locus = input_location; - - /* Detect do { ... } while (0) and don't generate loop construct. */ - if (!cond_is_first && cond && integer_zerop (cond)) - top = cond = NULL; - else - { - /* If we use a LOOP_EXPR here, we have to feed the whole thing - back through the main gimplifier to lower it. Given that we - have to gimplify the loop body NOW so that we can resolve - break/continue stmts, seems easier to just expand to gotos. */ - top = build1 (LABEL_EXPR, void_type_node, NULL_TREE); - } - - break_block = begin_bc_block (bc_break); - - if (top) - { - /* If we have an exit condition, then we build an IF with gotos either - out of the loop, or to the top of it. If there's no exit condition, - then we just build a jump back to the top. */ - exit = build_and_jump (&LABEL_EXPR_LABEL (top)); - if (cond) - { - gimplify_condition (&cond); - t = build_bc_goto (bc_break); - exit = build (COND_EXPR, void_type_node, cond, exit, t); - exit = fold (exit); - gimplify_stmt (&exit); - } - } - else - exit = NULL_TREE; - - cont_block = begin_bc_block (bc_continue); - - gimplify_stmt (&body); - if (incr && stmts_are_full_exprs_p ()) - incr = fold (build1 (CLEANUP_POINT_EXPR, void_type_node, incr)); - gimplify_stmt (&incr); - - body = finish_bc_block (cont_block, body); - - stmt_list = NULL; - - if (cond_is_first && cond) - { - entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE); - t = build_and_jump (&LABEL_EXPR_LABEL (entry)); - append_to_statement_list (t, &stmt_list); - } - else - entry = NULL_TREE; - - append_to_statement_list (top, &stmt_list); - append_to_statement_list (body, &stmt_list); - append_to_statement_list (incr, &stmt_list); - append_to_statement_list (entry, &stmt_list); - append_to_statement_list (exit, &stmt_list); - - annotate_all_with_locus (&stmt_list, stmt_locus); - - return finish_bc_block (break_block, stmt_list); -} - -/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the - prequeue and hand off to gimplify_c_loop. */ - -static enum gimplify_status -gimplify_for_stmt (tree *stmt_p, tree *next_p) -{ - tree stmt = *stmt_p; - tree init = FOR_INIT_STMT (stmt); - - if (init) - { - /* Reorganize the statements so that we do the right thing with a - CLEANUP_STMT. We want the FOR_STMT and nothing else to be in the - scope of the cleanup, so play with pointers to accomplish that. */ - FOR_INIT_STMT (stmt) = NULL_TREE; - chainon (init, stmt); - *stmt_p = init; - *next_p = TREE_CHAIN (stmt); - TREE_CHAIN (stmt) = NULL_TREE; - c_gimplify_stmt (stmt_p); - } - else - *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt), - FOR_EXPR (stmt), 1); - - return GS_ALL_DONE; -} - -/* Gimplify a WHILE_STMT node. */ - -static enum gimplify_status -gimplify_while_stmt (tree *stmt_p) -{ - tree stmt = *stmt_p; - *stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt), - NULL_TREE, 1); - return GS_ALL_DONE; -} - -/* Gimplify a DO_STMT node. */ - -static enum gimplify_status -gimplify_do_stmt (tree *stmt_p) -{ - tree stmt = *stmt_p; - *stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt), - NULL_TREE, 0); - return GS_ALL_DONE; -} - -/* Genericize an IF_STMT by turning it into a COND_EXPR. */ - -static enum gimplify_status -gimplify_if_stmt (tree *stmt_p) -{ - tree stmt, then_, else_; - - stmt = *stmt_p; - restart: - then_ = THEN_CLAUSE (stmt); - else_ = ELSE_CLAUSE (stmt); - - if (!then_) - then_ = build_empty_stmt (); - if (!else_) - else_ = build_empty_stmt (); - - stmt = build (COND_EXPR, void_type_node, IF_COND (stmt), then_, else_); - gimplify_condition (& TREE_OPERAND (stmt, 0)); - *stmt_p = stmt; - - /* Handle properly nested if-else chains via iteration instead of - mutual recursion between gimplify.c and c-simplify.c. */ - annotate_with_locus (stmt, input_location); - if (TREE_CODE (else_) == IF_STMT && !TREE_CHAIN (else_)) - { - stmt_p = &COND_EXPR_ELSE (stmt); - stmt = else_; - prep_stmt (stmt); - goto restart; - } - - return GS_OK; -} - -/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ - -static enum gimplify_status -gimplify_switch_stmt (tree *stmt_p) -{ - tree stmt = *stmt_p; - tree break_block, body; - location_t stmt_locus = input_location; - - break_block = begin_bc_block (bc_break); - - gimplify_condition (&SWITCH_COND (stmt)); - - body = SWITCH_BODY (stmt); - if (!body) - body = build_empty_stmt (); - - *stmt_p = build (SWITCH_EXPR, SWITCH_TYPE (stmt), SWITCH_COND (stmt), - body, NULL_TREE); - annotate_with_locus (*stmt_p, stmt_locus); - gimplify_stmt (stmt_p); - - *stmt_p = finish_bc_block (break_block, *stmt_p); - return GS_ALL_DONE; -} - -/* Genericize a RETURN_STMT by turning it into a RETURN_EXPR. */ - -static enum gimplify_status -gimplify_return_stmt (tree *stmt_p) -{ - tree expr = RETURN_STMT_EXPR (*stmt_p); - expr = build1 (RETURN_EXPR, void_type_node, expr); - if (stmts_are_full_exprs_p ()) - expr = build1 (CLEANUP_POINT_EXPR, void_type_node, expr); - *stmt_p = expr; - return GS_OK; -} - -/* Gimplifies a DECL_STMT node T. - - If a declaration V has an initial value I, create an expression 'V = I' - and insert it after the DECL_STMT. - - PRE_P is a queue for effects that should happen before the DECL_STMT. - - MID_P is a queue for effects that should happen after the DECL_STMT, - but before uses of the initialized decl. - - POST_P is a queue for effects that should happen after uses of the - initialized decl. - - Usually these last two will be the same, but they may need to be - different if the DECL_STMT is somehow embedded in an expression. */ - -static enum gimplify_status -gimplify_decl_stmt (tree *stmt_p) -{ - tree stmt = *stmt_p; - tree decl = DECL_STMT_DECL (stmt); - tree pre = NULL_TREE; - tree post = NULL_TREE; - - if (TREE_TYPE (decl) == error_mark_node) - { - *stmt_p = NULL; - return GS_ERROR; - } - - if (TREE_CODE (decl) == TYPE_DECL) - { - tree type = TREE_TYPE (decl); - if (TYPE_SIZE_UNIT (type) - && !TREE_CONSTANT (TYPE_SIZE_UNIT (type))) - { - /* This is a variable-sized array type. Simplify its size. */ - tree temp = TYPE_SIZE_UNIT (type); - gimplify_expr (&temp, &pre, &post, is_gimple_val, fb_rvalue); - } - } - - if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) - { - tree init = DECL_INITIAL (decl); - - if (!TREE_CONSTANT (DECL_SIZE (decl))) - { - tree pt_type = build_pointer_type (TREE_TYPE (decl)); - tree alloc, size; - - /* This is a variable-sized decl. Simplify its size and mark it - for deferred expansion. Note that mudflap depends on the format - of the emitted code: see mx_register_decls(). */ - - size = get_initialized_tmp_var (DECL_SIZE_UNIT (decl), &pre, &post); - DECL_DEFER_OUTPUT (decl) = 1; - alloc = build_function_call_expr - (implicit_built_in_decls[BUILT_IN_STACK_ALLOC], - tree_cons (NULL_TREE, - build1 (ADDR_EXPR, pt_type, decl), - tree_cons (NULL_TREE, size, NULL_TREE))); - append_to_compound_expr (alloc, &pre); - } - - if (init && init != error_mark_node) - { - if (!TREE_STATIC (decl)) - { - /* Do not warn about int x = x; as it is a GCC extension - to turn off this warning but only if warn_init_self - is zero. */ - if (init == decl && !warn_init_self) - TREE_NO_WARNING (decl) = 1; - - DECL_INITIAL (decl) = NULL_TREE; - init = build (MODIFY_EXPR, void_type_node, decl, init); - if (stmts_are_full_exprs_p ()) - init = build1 (CLEANUP_POINT_EXPR, void_type_node, init); - append_to_compound_expr (init, &pre); - } - else - { - /* We must still examine initializers for static variables - as they may contain a label address. */ - walk_tree (&init, force_labels_r, NULL, NULL); - } - } - - /* This decl isn't mentioned in the enclosing block, so add it to the - list of temps. FIXME it seems a bit of a kludge to say that - anonymous artificial vars aren't pushed, but everything else is. */ - if (DECL_ARTIFICIAL (decl) && DECL_NAME (decl) == NULL_TREE) - gimple_add_tmp_var (decl); - } - - append_to_compound_expr (post, &pre); - *stmt_p = pre; - return GS_OK; -} - -/* Gimplification of expression trees. */ - -/* Gimplify a C99 compound literal expression. This just means adding the - DECL_STMT before the current EXPR_STMT and using its anonymous decl - instead. */ - -static enum gimplify_status -gimplify_compound_literal_expr (tree *expr_p) -{ - tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p); - tree decl = DECL_STMT_DECL (decl_s); - - /* This decl isn't mentioned in the enclosing block, so add it to the - list of temps. FIXME it seems a bit of a kludge to say that - anonymous artificial vars aren't pushed, but everything else is. */ - if (DECL_NAME (decl) == NULL_TREE) - gimple_add_tmp_var (decl); - - gimplify_decl_stmt (&decl_s); - *expr_p = decl_s ? decl_s : decl; - return GS_OK; -} - -/* Do C-specific gimplification. Args are as for gimplify_expr. */ - -int -c_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, - tree *post_p ATTRIBUTE_UNUSED) -{ - enum tree_code code = TREE_CODE (*expr_p); - - if (STATEMENT_CODE_P (code)) - return c_gimplify_stmt (expr_p); - - switch (code) - { - case COMPOUND_LITERAL_EXPR: - return gimplify_compound_literal_expr (expr_p); - - case STMT_EXPR: - return gimplify_stmt_expr (expr_p); - - default: - return GS_UNHANDLED; - } -} - -/* Returns the final EXPR_STMT which represents the return value of a - STMT_EXPR, or NULL_TREE if none. */ - -tree -stmt_expr_last_stmt (tree stmt_expr) -{ - tree body = STMT_EXPR_STMT (stmt_expr); - tree last_stmt, substmt; - - /* Splice the last expression out of the STMT chain. */ - last_stmt = NULL_TREE; - for (substmt = COMPOUND_BODY (body); substmt; - substmt = TREE_CHAIN (substmt)) - if (TREE_CODE (substmt) != SCOPE_STMT) - last_stmt = substmt; - - if (last_stmt == NULL_TREE - || TREE_CODE (last_stmt) != EXPR_STMT - || (TREE_TYPE (last_stmt) - && VOID_TYPE_P (TREE_TYPE (last_stmt)))) - { - location_t loc; - if (last_stmt && EXPR_LOCUS (last_stmt)) - loc = *EXPR_LOCUS (last_stmt); - else if (EXPR_LOCUS (stmt_expr)) - loc = *EXPR_LOCUS (stmt_expr); - else - loc = input_location; - warning ("%Hstatement-expressions should end with a " - "non-void expression", &loc); - last_stmt = NULL_TREE; - } - -#if defined ENABLE_CHECKING - if (last_stmt && !is_last_stmt_of_scope (last_stmt)) - abort (); -#endif - - return last_stmt; -} - -/* Gimplify a STMT_EXPR. EXPR_P points to the expression to gimplify. - After gimplification, if the STMT_EXPR returns a value, EXPR_P will - point to a new temporary that holds that value; otherwise it will be - null. - - PRE_P points to the list where side effects that must happen before - *EXPR_P should be stored. */ - -static enum gimplify_status -gimplify_stmt_expr (tree *expr_p) -{ - tree body = STMT_EXPR_STMT (*expr_p); - - if (VOID_TYPE_P (TREE_TYPE (*expr_p))) - { - *expr_p = body; - return c_gimplify_stmt (expr_p); - } - else - { - tree last_stmt = stmt_expr_last_stmt (*expr_p); - tree last_expr = NULL_TREE; - - if (last_stmt) - { - last_expr = EXPR_STMT_EXPR (last_stmt); - - if (stmts_are_full_exprs_p ()) - last_expr = build1 (CLEANUP_POINT_EXPR, TREE_TYPE (last_expr), - last_expr); - EXPR_STMT_EXPR (last_stmt) = NULL_TREE; - } - - /* Genericize the block. */ - c_gimplify_stmt (&body); - - /* Now retrofit that last expression into the BIND_EXPR. */ - if (last_expr) - { - tree *sub_p; - - if (!STMT_EXPR_NO_SCOPE (*expr_p)) - { - /* Our BIND_EXPR will always be hidden within - a STATEMENT_LIST. Discard that. */ - body = expr_first (body); - sub_p = &BIND_EXPR_BODY (body); - - /* Append the last expression to the end of the BIND_EXPR. - We'll now re-process this, and let voidify_wrapper_expr - do its job. */ - append_to_statement_list_force (last_expr, sub_p); - TREE_TYPE (body) = TREE_TYPE (last_expr); - } - else - append_to_compound_expr (last_expr, &body); - } - - *expr_p = body; - return GS_OK; - } -} - -/* Code generation. */ - -/* Miscellaneous helpers. */ - -#if defined ENABLE_CHECKING -/* Return nonzero if STMT is the last statement of its scope. */ - -static int -is_last_stmt_of_scope (tree stmt) -{ - return (TREE_CHAIN (stmt) == NULL_TREE - || (TREE_CODE (TREE_CHAIN (stmt)) == SCOPE_STMT - && SCOPE_END_P (TREE_CHAIN (stmt)))); -} -#endif diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9d990ee3642..25c72524de4 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,8 @@ +2004-05-13 Diego Novillo + + * cp-gimplify.c: Rename from cp-simplify.c. + * Make-lang.in, optimize.c: Update. + 2004-05-13 Diego Novillo Merge from tree-ssa-20020619-branch. See diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in index bf4b0fe850f..12decae82f1 100644 --- a/gcc/cp/Make-lang.in +++ b/gcc/cp/Make-lang.in @@ -74,7 +74,7 @@ g++-cross$(exeext): g++$(exeext) CXX_C_OBJS = attribs.o c-common.o c-format.o c-pragma.o c-semantics.o c-lex.o \ c-dump.o $(CXX_TARGET_OBJS) c-pretty-print.o c-opts.o c-pch.o \ c-incpath.o cppdefault.o c-ppoutput.o c-cppbuiltin.o prefix.o \ - c-simplify.o tree-inline.o + c-gimplify.o tree-inline.o # Language-specific object files. CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ @@ -82,7 +82,7 @@ CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \ cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \ cp/search.o cp/semantics.o cp/tree.o cp/repo.o cp/dump.o cp/optimize.o \ cp/mangle.o cp/cp-lang.o cp/name-lookup.o cp/cxx-pretty-print.o \ - cp/cp-simplify.o tree-mudflap.o cp/cp-mudflap.o + cp/cp-gimplify.o tree-mudflap.o cp/cp-mudflap.o # Use strict warnings for this front end. cp-warn = $(STRICT_WARN) $(WERROR) @@ -259,13 +259,13 @@ cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h tree-inline.h cgraph.h cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \ - input.h $(PARAMS_H) debug.h tree-inline.h tree-simple.h + input.h $(PARAMS_H) debug.h tree-inline.h tree-gimple.h cp/mangle.o: cp/mangle.c $(CXX_TREE_H) $(TM_H) toplev.h real.h gt-cp-mangle.h \ $(TARGET_H) $(TM_P_H) cp/parser.o: cp/parser.c $(CXX_TREE_H) $(TM_H) diagnostic.h gt-cp-parser.h \ output.h -cp/cp-simplify.o: cp/cp-simplify.c $(CXX_TREE_H) toplev.h c-common.h \ +cp/cp-gimplify.o: cp/cp-gimplify.c $(CXX_TREE_H) toplev.h c-common.h \ $(TM_H) coretypes.h cp/cp-mudflap.o: cp/cp-mudflap.c $(CXX_TREE_H) toplev.h c-common.h \ $(TM_H) coretypes.h diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c new file mode 100644 index 00000000000..f82ed61eb7a --- /dev/null +++ b/gcc/cp/cp-gimplify.c @@ -0,0 +1,236 @@ +/* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c. + + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Jason Merrill + +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 "tree.h" +#include "cp-tree.h" +#include "c-common.h" +#include "toplev.h" +#include "tree-gimple.h" + +static void genericize_try_block (tree *); +static void genericize_catch_block (tree *); +static void genericize_eh_spec_block (tree *); +static void gimplify_must_not_throw_expr (tree *, tree *); +static void cp_gimplify_init_expr (tree *, tree *, tree *); + +/* Genericize a C++ _STMT. Called from c_gimplify_stmt. */ + +int +cp_gimplify_stmt (tree *stmt_p, tree *next_p ATTRIBUTE_UNUSED) +{ + tree stmt = *stmt_p; + switch (TREE_CODE (stmt)) + { + case TRY_BLOCK: + genericize_try_block (stmt_p); + return 1; + + case HANDLER: + genericize_catch_block (stmt_p); + return 1; + + case EH_SPEC_BLOCK: + genericize_eh_spec_block (stmt_p); + return 1; + + case USING_STMT: + /* Just ignore for now. Eventually we will want to pass this on to + the debugger. */ + *stmt_p = build_empty_stmt (); + return 1; + + default: + break; + } + return 0; +} + +/* Genericize a TRY_BLOCK. */ + +static void +genericize_try_block (tree *stmt_p) +{ + tree body = TRY_STMTS (*stmt_p); + tree cleanup = TRY_HANDLERS (*stmt_p); + + c_gimplify_stmt (&body); + + if (CLEANUP_P (*stmt_p)) + /* A cleanup is an expression, so it doesn't need to be genericized. */; + else + c_gimplify_stmt (&cleanup); + + *stmt_p = build (TRY_CATCH_EXPR, void_type_node, body, cleanup); +} + +/* Genericize a HANDLER by converting to a CATCH_EXPR. */ + +static void +genericize_catch_block (tree *stmt_p) +{ + tree type = HANDLER_TYPE (*stmt_p); + tree body = HANDLER_BODY (*stmt_p); + + c_gimplify_stmt (&body); + + /* FIXME should the caught type go in TREE_TYPE? */ + *stmt_p = build (CATCH_EXPR, void_type_node, type, body); +} + +/* Genericize an EH_SPEC_BLOCK by converting it to a + TRY_CATCH_EXPR/EH_FILTER_EXPR pair. */ + +static void +genericize_eh_spec_block (tree *stmt_p) +{ + tree body = EH_SPEC_STMTS (*stmt_p); + tree allowed = EH_SPEC_RAISES (*stmt_p); + tree failure = build_call (call_unexpected_node, + tree_cons (NULL_TREE, build_exc_ptr (), + NULL_TREE)); + c_gimplify_stmt (&body); + + *stmt_p = gimple_build_eh_filter (body, allowed, failure); +} + +/* Do C++-specific gimplification. Args are as for gimplify_expr. */ + +int +cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + switch (TREE_CODE (*expr_p)) + { + case PTRMEM_CST: + *expr_p = cplus_expand_constant (*expr_p); + return GS_OK; + + case AGGR_INIT_EXPR: + simplify_aggr_init_expr (expr_p); + return GS_OK; + + case THROW_EXPR: + /* FIXME communicate throw type to backend, probably by moving + THROW_EXPR into ../tree.def. */ + *expr_p = TREE_OPERAND (*expr_p, 0); + return GS_OK; + + case MUST_NOT_THROW_EXPR: + gimplify_must_not_throw_expr (expr_p, pre_p); + return GS_OK; + + case INIT_EXPR: + case MODIFY_EXPR: + cp_gimplify_init_expr (expr_p, pre_p, post_p); + return GS_OK; + + case EMPTY_CLASS_EXPR: + { + /* Yes, an INTEGER_CST with RECORD_TYPE. */ + tree i = build_int_2 (0, 0); + TREE_TYPE (i) = TREE_TYPE (*expr_p); + *expr_p = i; + } + return GS_OK; + + case BASELINK: + *expr_p = BASELINK_FUNCTIONS (*expr_p); + return GS_OK; + + default: + return c_gimplify_expr (expr_p, pre_p, post_p); + } +} + +/* Gimplify initialization from an AGGR_INIT_EXPR. */ + +static void +cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) +{ + tree from = TREE_OPERAND (*expr_p, 1); + tree to = TREE_OPERAND (*expr_p, 0); + tree sub; + + /* If we are initializing something from a TARGET_EXPR, strip the + TARGET_EXPR and initialize it directly. */ + /* What about code that pulls out the temp and uses it elsewhere? I + think that such code never uses the TARGET_EXPR as an initializer. If + I'm wrong, we'll abort because the temp won't have any RTL. In that + case, I guess we'll need to replace references somehow. */ + if (TREE_CODE (from) == TARGET_EXPR) + from = TARGET_EXPR_INITIAL (from); + + sub = from; + + /* If we are initializing from a STMT_EXPR, extract the returned + expression. */ + if (TREE_CODE (from) == STMT_EXPR) + sub = EXPR_STMT_EXPR (stmt_expr_last_stmt (from)); + + /* Look through any COMPOUND_EXPRs. */ + while (TREE_CODE (sub) == COMPOUND_EXPR) + sub = TREE_OPERAND (sub, 1); + + /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and + replace the slot operand with our target. + + Should we add a target parm to gimplify_expr instead? No, as in this + case we want to replace the INIT_EXPR. */ + if (TREE_CODE (sub) == AGGR_INIT_EXPR) + { + gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); + TREE_OPERAND (sub, 2) = to; + *expr_p = from; + + /* The initialization is now a side-effect, so the container can + become void. This is important for a STMT_EXPR, so we don't try + to voidify it later by creating a temporary. */ + if (from != sub) + TREE_TYPE (from) = void_type_node; + } +} + +/* Gimplify a MUST_NOT_THROW_EXPR. */ + +static void +gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p) +{ + tree stmt = *expr_p; + tree temp = voidify_wrapper_expr (stmt); + tree body = TREE_OPERAND (stmt, 0); + + gimplify_stmt (&body); + + stmt = gimple_build_eh_filter (body, NULL_TREE, + build_call (terminate_node, NULL_TREE)); + + if (temp) + { + append_to_statement_list (stmt, pre_p); + *expr_p = temp; + } + else + *expr_p = stmt; +} diff --git a/gcc/cp/cp-simplify.c b/gcc/cp/cp-simplify.c deleted file mode 100644 index af302ee5476..00000000000 --- a/gcc/cp/cp-simplify.c +++ /dev/null @@ -1,236 +0,0 @@ -/* C++-specific tree lowering bits; see also c-simplify.c and tree-simple.c. - - Copyright (C) 2002, 2003 Free Software Foundation, Inc. - Contributed by Jason Merrill - -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 "tree.h" -#include "cp-tree.h" -#include "c-common.h" -#include "toplev.h" -#include "tree-simple.h" - -static void genericize_try_block (tree *); -static void genericize_catch_block (tree *); -static void genericize_eh_spec_block (tree *); -static void gimplify_must_not_throw_expr (tree *, tree *); -static void cp_gimplify_init_expr (tree *, tree *, tree *); - -/* Genericize a C++ _STMT. Called from c_gimplify_stmt. */ - -int -cp_gimplify_stmt (tree *stmt_p, tree *next_p ATTRIBUTE_UNUSED) -{ - tree stmt = *stmt_p; - switch (TREE_CODE (stmt)) - { - case TRY_BLOCK: - genericize_try_block (stmt_p); - return 1; - - case HANDLER: - genericize_catch_block (stmt_p); - return 1; - - case EH_SPEC_BLOCK: - genericize_eh_spec_block (stmt_p); - return 1; - - case USING_STMT: - /* Just ignore for now. Eventually we will want to pass this on to - the debugger. */ - *stmt_p = build_empty_stmt (); - return 1; - - default: - break; - } - return 0; -} - -/* Genericize a TRY_BLOCK. */ - -static void -genericize_try_block (tree *stmt_p) -{ - tree body = TRY_STMTS (*stmt_p); - tree cleanup = TRY_HANDLERS (*stmt_p); - - c_gimplify_stmt (&body); - - if (CLEANUP_P (*stmt_p)) - /* A cleanup is an expression, so it doesn't need to be genericized. */; - else - c_gimplify_stmt (&cleanup); - - *stmt_p = build (TRY_CATCH_EXPR, void_type_node, body, cleanup); -} - -/* Genericize a HANDLER by converting to a CATCH_EXPR. */ - -static void -genericize_catch_block (tree *stmt_p) -{ - tree type = HANDLER_TYPE (*stmt_p); - tree body = HANDLER_BODY (*stmt_p); - - c_gimplify_stmt (&body); - - /* FIXME should the caught type go in TREE_TYPE? */ - *stmt_p = build (CATCH_EXPR, void_type_node, type, body); -} - -/* Genericize an EH_SPEC_BLOCK by converting it to a - TRY_CATCH_EXPR/EH_FILTER_EXPR pair. */ - -static void -genericize_eh_spec_block (tree *stmt_p) -{ - tree body = EH_SPEC_STMTS (*stmt_p); - tree allowed = EH_SPEC_RAISES (*stmt_p); - tree failure = build_call (call_unexpected_node, - tree_cons (NULL_TREE, build_exc_ptr (), - NULL_TREE)); - c_gimplify_stmt (&body); - - *stmt_p = gimple_build_eh_filter (body, allowed, failure); -} - -/* Do C++-specific gimplification. Args are as for gimplify_expr. */ - -int -cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) -{ - switch (TREE_CODE (*expr_p)) - { - case PTRMEM_CST: - *expr_p = cplus_expand_constant (*expr_p); - return GS_OK; - - case AGGR_INIT_EXPR: - simplify_aggr_init_expr (expr_p); - return GS_OK; - - case THROW_EXPR: - /* FIXME communicate throw type to backend, probably by moving - THROW_EXPR into ../tree.def. */ - *expr_p = TREE_OPERAND (*expr_p, 0); - return GS_OK; - - case MUST_NOT_THROW_EXPR: - gimplify_must_not_throw_expr (expr_p, pre_p); - return GS_OK; - - case INIT_EXPR: - case MODIFY_EXPR: - cp_gimplify_init_expr (expr_p, pre_p, post_p); - return GS_OK; - - case EMPTY_CLASS_EXPR: - { - /* Yes, an INTEGER_CST with RECORD_TYPE. */ - tree i = build_int_2 (0, 0); - TREE_TYPE (i) = TREE_TYPE (*expr_p); - *expr_p = i; - } - return GS_OK; - - case BASELINK: - *expr_p = BASELINK_FUNCTIONS (*expr_p); - return GS_OK; - - default: - return c_gimplify_expr (expr_p, pre_p, post_p); - } -} - -/* Gimplify initialization from an AGGR_INIT_EXPR. */ - -static void -cp_gimplify_init_expr (tree *expr_p, tree *pre_p, tree *post_p) -{ - tree from = TREE_OPERAND (*expr_p, 1); - tree to = TREE_OPERAND (*expr_p, 0); - tree sub; - - /* If we are initializing something from a TARGET_EXPR, strip the - TARGET_EXPR and initialize it directly. */ - /* What about code that pulls out the temp and uses it elsewhere? I - think that such code never uses the TARGET_EXPR as an initializer. If - I'm wrong, we'll abort because the temp won't have any RTL. In that - case, I guess we'll need to replace references somehow. */ - if (TREE_CODE (from) == TARGET_EXPR) - from = TARGET_EXPR_INITIAL (from); - - sub = from; - - /* If we are initializing from a STMT_EXPR, extract the returned - expression. */ - if (TREE_CODE (from) == STMT_EXPR) - sub = EXPR_STMT_EXPR (stmt_expr_last_stmt (from)); - - /* Look through any COMPOUND_EXPRs. */ - while (TREE_CODE (sub) == COMPOUND_EXPR) - sub = TREE_OPERAND (sub, 1); - - /* If we are initializing from an AGGR_INIT_EXPR, drop the INIT_EXPR and - replace the slot operand with our target. - - Should we add a target parm to gimplify_expr instead? No, as in this - case we want to replace the INIT_EXPR. */ - if (TREE_CODE (sub) == AGGR_INIT_EXPR) - { - gimplify_expr (&to, pre_p, post_p, is_gimple_lvalue, fb_lvalue); - TREE_OPERAND (sub, 2) = to; - *expr_p = from; - - /* The initialization is now a side-effect, so the container can - become void. This is important for a STMT_EXPR, so we don't try - to voidify it later by creating a temporary. */ - if (from != sub) - TREE_TYPE (from) = void_type_node; - } -} - -/* Gimplify a MUST_NOT_THROW_EXPR. */ - -static void -gimplify_must_not_throw_expr (tree *expr_p, tree *pre_p) -{ - tree stmt = *expr_p; - tree temp = voidify_wrapper_expr (stmt); - tree body = TREE_OPERAND (stmt, 0); - - gimplify_stmt (&body); - - stmt = gimple_build_eh_filter (body, NULL_TREE, - build_call (terminate_node, NULL_TREE)); - - if (temp) - { - append_to_statement_list (stmt, pre_p); - *expr_p = temp; - } - else - *expr_p = stmt; -} diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 1be4d8afdcc..7f45ae9123c 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -40,7 +40,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "diagnostic.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" /* Prototypes. */ diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog index 8939fc452d3..d8185353d25 100644 --- a/gcc/fortran/ChangeLog +++ b/gcc/fortran/ChangeLog @@ -1,3 +1,9 @@ +2004-05-13 Diego Novillo + + * Make-lang.in, f95-lang.c, trans-array.c, trans-decl.c, + trans-expr.c, trans-intrinsic.c, trans-io.c, trans-stmt.c, + trans.c: Rename tree-simple.[ch] to tree-gimple.[ch]. + 2004-05-13 Victor Leikehman PR fortran/15314 diff --git a/gcc/fortran/Make-lang.in b/gcc/fortran/Make-lang.in index a38834b4713..f1acba838bf 100644 --- a/gcc/fortran/Make-lang.in +++ b/gcc/fortran/Make-lang.in @@ -81,7 +81,7 @@ F95_OBJS = $(F95_PARSER_OBJS) \ # We rely on c-semantics to expand from GIMPLE to RTL. # This should go away once a real GIMPLE expander is available. F95_ADDITIONAL_OBJS = \ - tree-cfg.o tree-dfa.o tree-optimize.o tree-simple.o \ + tree-cfg.o tree-dfa.o tree-optimize.o tree-gimple.o \ tree-ssa.o tree-ssa-ccp.o tree-ssa-dce.o \ tree-alias-common.o tree-alias-type.o gimplify.o stor-layout.o diff --git a/gcc/fortran/f95-lang.c b/gcc/fortran/f95-lang.c index 51ce3c4e530..f5cc66ec53d 100644 --- a/gcc/fortran/f95-lang.c +++ b/gcc/fortran/f95-lang.c @@ -28,7 +28,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "flags.h" #include "langhooks.h" #include "langhooks-def.h" diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 452b0fec81c..2d95550bc1b 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -80,7 +80,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include #include "ggc.h" #include "toplev.h" diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 79e8cf6927e..c1e80508457 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -26,7 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "coretypes.h" #include "tree.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "ggc.h" #include "toplev.h" #include "tm.h" diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 1f98f9e1a89..b0f4139d24d 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -31,7 +31,7 @@ Boston, MA 02111-1307, USA. */ #include "ggc.h" #include "toplev.h" #include "real.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "flags.h" #include #include @@ -374,7 +374,7 @@ gfc_conv_unary_op (enum tree_code code, gfc_se * se, gfc_expr * expr) /* TRUTH_NOT_EXPR is not a "true" unary operator in GCC. We must convert it to a compare to 0 (e.g. EQ_EXPR (op1, 0)). - All other unary operators have an equivalent SIMPLE unary operator */ + All other unary operators have an equivalent GIMPLE unary operator */ if (code == TRUTH_NOT_EXPR) se->expr = build (EQ_EXPR, type, operand.expr, integer_zero_node); else @@ -796,7 +796,7 @@ gfc_conv_expr_op (gfc_se * se, gfc_expr * expr) break; /* EQV and NEQV only work on logicals, but since we represent them - as integers, we can use EQ_EXPR and NE_EXPR for them in SIMPLE. */ + as integers, we can use EQ_EXPR and NE_EXPR for them in GIMPLE. */ case INTRINSIC_EQ: case INTRINSIC_EQV: code = EQ_EXPR; diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index fb3ceb2f6b1..b58c298b0b7 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -31,7 +31,7 @@ Boston, MA 02111-1307, USA. */ #include "ggc.h" #include "toplev.h" #include "real.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "flags.h" #include #include diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c index d18bb794195..66fffab12e1 100644 --- a/gcc/fortran/trans-io.c +++ b/gcc/fortran/trans-io.c @@ -24,7 +24,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include #include "ggc.h" #include "toplev.h" diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 0de62a5367c..6c2e669994b 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -25,7 +25,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include #include "ggc.h" #include "toplev.h" diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index aed764d0a36..a423ac95062 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include #include "ggc.h" #include "toplev.h" @@ -443,7 +443,7 @@ gfc_trans_code (gfc_code * code) gfc_start_block (&block); - /* Translate statements one by one to SIMPLE trees until we reach + /* Translate statements one by one to GIMPLE trees until we reach the end of this gfc_code branch. */ for (; code; code = code->next) { diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index af2760279bc..56f02b7a1ee 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -27,7 +27,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "rtl.h" #include "errors.h" #include "varray.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "diagnostic.h" #include "langhooks.h" diff --git a/gcc/gimplify.c b/gcc/gimplify.c index dda218beab4..787dbc34999 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -30,7 +30,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "rtl.h" #include "errors.h" #include "varray.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "diagnostic.h" #include "langhooks.h" @@ -3029,7 +3029,7 @@ gimplify_to_stmt_list (tree *stmt_p) GIMPLE_TEST_F points to a function that takes a tree T and returns nonzero if T is in the GIMPLE form requested by the - caller. The GIMPLE predicates are in tree-simple.c. + caller. The GIMPLE predicates are in tree-gimple.c. This test is used twice. Before gimplification, the test is invoked to determine whether *EXPR_P is already gimple enough. If diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index b7cb8c4630c..dfbf10d5acd 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,8 @@ +2004-05-13 Diego Novillo + + * Make-lang.in, expr.c, java-gimplify.c: Rename + tree-simple.[ch] to tree-gimple.[ch]. + 2004-05-14 Ranjit Mathew * java-gimplify.c (java_gimplify_expr): Correct minor typos. diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in index db3ac9d5531..367627362dc 100644 --- a/gcc/java/Make-lang.in +++ b/gcc/java/Make-lang.in @@ -334,7 +334,7 @@ java/xref.o: java/xref.c java/xref.h $(CONFIG_H) $(JAVA_TREE_H) toplev.h \ java/zextract.o: java/zextract.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ java/zipfile.h java/java-gimplify.o: java/java-gimplify.c $(CONFIG_H) $(SYSTEM_H) \ - coretypes.h $(TM_H) $(JAVA_TREE_H) tree-simple.h toplev.h + coretypes.h $(TM_H) $(JAVA_TREE_H) tree-gimple.h toplev.h java/parse-scan.o: java/parse-scan.c $(CONFIG_H) $(SYSTEM_H) \ coretypes.h $(TM_H) toplev.h $(JAVA_LEX_C) java/parse.h java/lex.h input.h diff --git a/gcc/java/expr.c b/gcc/java/expr.c index a63309ec9a4..aa0697420a0 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -43,7 +43,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "toplev.h" #include "except.h" #include "ggc.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "target.h" static void flush_quick_stack (void); diff --git a/gcc/java/java-gimplify.c b/gcc/java/java-gimplify.c index f32a4c809b0..987351c2102 100644 --- a/gcc/java/java-gimplify.c +++ b/gcc/java/java-gimplify.c @@ -30,7 +30,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ #include "tree.h" #include "java-tree.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "toplev.h" static tree java_gimplify_case_expr (tree); diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 58e4eb6b21d..c82b5fd4f3f 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -26,7 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "toplev.h" #include "tree.h" #include "tree-inline.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "rtl.h" #include "insn-config.h" #include "integrate.h" diff --git a/gcc/tree-alias-ander.c b/gcc/tree-alias-ander.c index b3b14d1fa12..3f277342836 100644 --- a/gcc/tree-alias-ander.c +++ b/gcc/tree-alias-ander.c @@ -41,7 +41,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "tree-flow.h" #include "tree-inline.h" #include "varray.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "splay-tree.h" #include "engine/util.h" #include "libcompat/regions.h" diff --git a/gcc/tree-alias-common.c b/gcc/tree-alias-common.c index cd36eef5942..f7b6fed5f34 100644 --- a/gcc/tree-alias-common.c +++ b/gcc/tree-alias-common.c @@ -45,7 +45,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "tree-inline.h" #include "varray.h" #include "c-tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "hashtab.h" #include "function.h" #include "cgraph.h" diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c index fe963041a05..8094d950da3 100644 --- a/gcc/tree-complex.c +++ b/gcc/tree-complex.c @@ -24,7 +24,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree.h" #include "tm.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-iterator.h" #include "tree-pass.h" #include "flags.h" diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index cda68487efb..2a71ef20fe6 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -39,7 +39,7 @@ Boston, MA 02111-1307, USA. */ #include "function.h" #include "diagnostic.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-flow.h" #include "tree-inline.h" #include "tree-alias-common.h" diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index 853eb1a41eb..76f97a4ebf5 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -26,7 +26,7 @@ Boston, MA 02111-1307, USA. */ #include "hard-reg-set.h" #include "basic-block.h" #include "hashtab.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-ssa-operands.h" /* Forward declare structures for the garbage collector GTY markers. */ diff --git a/gcc/tree-gimple.c b/gcc/tree-gimple.c new file mode 100644 index 00000000000..dbe2966e1e9 --- /dev/null +++ b/gcc/tree-gimple.c @@ -0,0 +1,642 @@ +/* Functions to analyze and validate GIMPLE trees. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Diego Novillo + Rewritten by Jason Merrill + +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 "ggc.h" +#include "tm.h" +#include "tree.h" +#include "tree-gimple.h" +#include "output.h" +#include "rtl.h" +#include "expr.h" +#include "bitmap.h" + +/* GCC GIMPLE structure + + Inspired by the SIMPLE C grammar at + + http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html + + function: + FUNCTION_DECL + DECL_SAVED_TREE -> block + block: + BIND_EXPR + BIND_EXPR_VARS -> DECL chain + BIND_EXPR_BLOCK -> BLOCK + BIND_EXPR_BODY -> compound-stmt + compound-stmt: + COMPOUND_EXPR + op0 -> non-compound-stmt + op1 -> stmt + | EXPR_VEC + (or other alternate solution) + stmt: compound-stmt | non-compound-stmt + non-compound-stmt: + block + | if-stmt + | switch-stmt + | jump-stmt + | label-stmt + | try-stmt + | modify-stmt + | call-stmt + if-stmt: + COND_EXPR + op0 -> condition + op1 -> stmt + op2 -> stmt + switch-stmt: + SWITCH_EXPR + op0 -> val + op1 -> stmt + op2 -> array of case labels (as LABEL_DECLs?) + FIXME: add case value info + jump-stmt: + GOTO_EXPR + op0 -> LABEL_DECL | '*' ID + | RETURN_EXPR + op0 -> modify-stmt | NULL_TREE + (maybe -> RESULT_DECL | NULL_TREE? seems like some of expand_return + depends on getting a MODIFY_EXPR.) + | THROW_EXPR? do we need/want such a thing for opts, perhaps + to generate an ERT_THROW region? I think so. + Hmm...this would only work at the GIMPLE level, where we know that + the call args don't have any EH impact. Perhaps + annotation of the CALL_EXPR would work better. + | RESX_EXPR + label-stmt: + LABEL_EXPR + op0 -> LABEL_DECL + | CASE_LABEL_EXPR + CASE_LOW -> val | NULL_TREE + CASE_HIGH -> val | NULL_TREE + CASE_LABEL -> LABEL_DECL FIXME + try-stmt: + TRY_CATCH_EXPR + op0 -> stmt + op1 -> handler + | TRY_FINALLY_EXPR + op0 -> stmt + op1 -> stmt + handler: + catch-seq + | EH_FILTER_EXPR + | stmt + modify-stmt: + MODIFY_EXPR + op0 -> lhs + op1 -> rhs + call-stmt: CALL_EXPR + op0 -> ID | '&' ID + op1 -> arglist + + addr-expr-arg : compref | ID + lhs: addr-expr-arg | '*' ID | bitfieldref + min-lval: ID | '*' ID + bitfieldref : + BIT_FIELD_REF + op0 -> compref | min-lval + op1 -> CONST + op2 -> CONST + compref : + COMPONENT_REF + op0 -> compref | min-lval + | ARRAY_REF + op0 -> compref | min-lval + op1 -> val + | REALPART_EXPR + | IMAGPART_EXPR + + condition : val | val relop val + val : ID | CONST + + rhs : varname | CONST + | '*' ID + | '&' addr-expr-arg + | call_expr + | unop val + | val binop val + | '(' cast ')' val + + (cast here stands for all valid C typecasts) + + unop + : '+' + | '-' + | '!' + | '~' + + binop + : relop | '-' + | '+' + | '/' + | '*' + | '%' + | '&' + | '|' + | '<<' + | '>>' + | '^' + + relop + : '<' + | '<=' + | '>' + | '>=' + | '==' + | '!=' + +*/ + +static inline bool is_gimple_id (tree); + +/* Validation of GIMPLE expressions. */ + +/* Return nonzero if T is a GIMPLE RHS: + + rhs : varname | CONST + | '*' ID + | '&' varname_or_temp + | call_expr + | unop val + | val binop val + | '(' cast ')' val + | > + + The last option is only valid GIMPLE for vector and complex types; + aggregate types should have their constructors decomposed. */ + +bool +is_gimple_rhs (tree t) +{ + enum tree_code code = TREE_CODE (t); + + switch (TREE_CODE_CLASS (code)) + { + case '1': + case '2': + case '<': + return 1; + + default: + break; + } + + switch (code) + { + case TRUTH_NOT_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case TRUTH_XOR_EXPR: + case ADDR_EXPR: + case CALL_EXPR: + case CONSTRUCTOR: + case COMPLEX_EXPR: + /* FIXME lower VA_ARG_EXPR. */ + case VA_ARG_EXPR: + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return 1; + + default: + break; + } + + if (is_gimple_lvalue (t) || is_gimple_val (t)) + return 1; + + return 0; +} + +/* Returns nonzero if T is a valid CONSTRUCTOR component in GIMPLE, either + a val or another CONSTRUCTOR. */ + +bool +is_gimple_constructor_elt (tree t) +{ + return (is_gimple_val (t) + || TREE_CODE (t) == CONSTRUCTOR); +} + +/* Return nonzero if T is a valid LHS for a GIMPLE assignment expression. */ + +bool +is_gimple_lvalue (tree t) +{ + return (is_gimple_addr_expr_arg (t) + || TREE_CODE (t) == INDIRECT_REF + /* These are complex lvalues, but don't have addresses, so they + go here. */ + || TREE_CODE (t) == BIT_FIELD_REF); +} + + +/* Return nonzero if T is a GIMPLE condition: + + condexpr + : val + | val relop val */ + +bool +is_gimple_condexpr (tree t) +{ + return (is_gimple_val (t) + || TREE_CODE_CLASS (TREE_CODE (t)) == '<'); +} + + +/* Return nonzero if T is a valid operand for '&': + + varname + : arrayref + | compref + | ID */ + +bool +is_gimple_addr_expr_arg (tree t) +{ + return (is_gimple_id (t) + || TREE_CODE (t) == ARRAY_REF + || TREE_CODE (t) == COMPONENT_REF + || TREE_CODE (t) == REALPART_EXPR + || TREE_CODE (t) == IMAGPART_EXPR); +} + +/* Return nonzero if T is function invariant. Or rather a restricted + form of function invariant. */ + +bool +is_gimple_min_invariant (tree t) +{ + switch (TREE_CODE (t)) + { + case ADDR_EXPR: + return TREE_INVARIANT (t); + + case INTEGER_CST: + case REAL_CST: + case STRING_CST: + case COMPLEX_CST: + case VECTOR_CST: + return !TREE_OVERFLOW (t); + + default: + return false; + } +} + +/* Return nonzero if T looks like a valid GIMPLE statement. */ + +bool +is_gimple_stmt (tree t) +{ + enum tree_code code = TREE_CODE (t); + + if (IS_EMPTY_STMT (t)) + return 1; + + switch (code) + { + case BIND_EXPR: + case COND_EXPR: + /* These are only valid if they're void. */ + return VOID_TYPE_P (TREE_TYPE (t)); + + case SWITCH_EXPR: + case GOTO_EXPR: + case RETURN_EXPR: + case LABEL_EXPR: + case CASE_LABEL_EXPR: + case TRY_CATCH_EXPR: + case TRY_FINALLY_EXPR: + case EH_FILTER_EXPR: + case CATCH_EXPR: + case ASM_EXPR: + case RESX_EXPR: + case PHI_NODE: + case STATEMENT_LIST: + /* These are always void. */ + return 1; + + case VA_ARG_EXPR: + /* FIXME this should be lowered. */ + return 1; + + case COMPOUND_EXPR: + /* FIXME should we work harder to make COMPOUND_EXPRs void? */ + case CALL_EXPR: + case MODIFY_EXPR: + /* These are valid regardless of their type. */ + return 1; + + default: + return 0; + } +} + +/* Return nonzero if T is a variable. */ + +bool +is_gimple_variable (tree t) +{ + return (TREE_CODE (t) == VAR_DECL + || TREE_CODE (t) == PARM_DECL + || TREE_CODE (t) == RESULT_DECL + || TREE_CODE (t) == SSA_NAME); +} + +/* Return nonzero if T is a GIMPLE identifier (something with an address). */ + +static inline bool +is_gimple_id (tree t) +{ + return (is_gimple_variable (t) + || TREE_CODE (t) == FUNCTION_DECL + || TREE_CODE (t) == LABEL_DECL + /* Allow string constants, since they are addressable. */ + || TREE_CODE (t) == STRING_CST); +} + +/* Return nonzero if TYPE is a suitable type for a scalar register + variable. */ + +bool +is_gimple_reg_type (tree type) +{ + return (!AGGREGATE_TYPE_P (type) + && TREE_CODE (type) != COMPLEX_TYPE); +} + + +/* Return nonzero if T is a scalar register variable. */ + +bool +is_gimple_reg (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + return (is_gimple_variable (t) + && is_gimple_reg_type (TREE_TYPE (t)) + /* A volatile decl is not acceptable because we can't reuse it as + needed. We need to copy it into a temp first. */ + && ! TREE_THIS_VOLATILE (t) + && ! TREE_ADDRESSABLE (t) + && ! needs_to_live_in_memory (t)); +} + +/* Return nonzero if T is a GIMPLE variable whose address is not needed. */ + +bool +is_gimple_non_addressable (tree t) +{ + if (TREE_CODE (t) == SSA_NAME) + t = SSA_NAME_VAR (t); + + return (is_gimple_variable (t) + && ! TREE_ADDRESSABLE (t) + && ! needs_to_live_in_memory (t)); +} + +/* Return nonzero if T is a GIMPLE rvalue, i.e. an identifier or a + constant. */ + +bool +is_gimple_val (tree t) +{ + /* Make loads from volatiles and memory vars explicit. */ + if (is_gimple_variable (t) + && is_gimple_reg_type (TREE_TYPE (t)) + && !is_gimple_reg (t)) + return 0; + + /* FIXME make these decls. That can happen only when we expose the + entire landing-pad construct at the tree level. */ + if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR) + return 1; + + return (is_gimple_variable (t) || is_gimple_min_invariant (t)); +} + + +/* Return true if T is a GIMPLE minimal lvalue, of the form + + min_lval: ID | '(' '*' ID ')' + + This never actually appears in the original SIMPLE grammar, but is + repeated in several places. */ + +bool +is_gimple_min_lval (tree t) +{ + return (is_gimple_id (t) + || TREE_CODE (t) == INDIRECT_REF); +} + +/* Return nonzero if T is a typecast operation of the form + '(' cast ')' val. */ + +bool +is_gimple_cast (tree t) +{ + return (TREE_CODE (t) == NOP_EXPR + || TREE_CODE (t) == CONVERT_EXPR + || TREE_CODE (t) == FIX_TRUNC_EXPR + || TREE_CODE (t) == FIX_CEIL_EXPR + || TREE_CODE (t) == FIX_FLOOR_EXPR + || TREE_CODE (t) == FIX_ROUND_EXPR); +} + + +/* If T makes a function call, return the corresponding CALL_EXPR operand. + Otherwise, return NULL_TREE. */ + +tree +get_call_expr_in (tree t) +{ + if (TREE_CODE (t) == CALL_EXPR) + return t; + else if (TREE_CODE (t) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) + return TREE_OPERAND (t, 1); + else if (TREE_CODE (t) == RETURN_EXPR + && TREE_OPERAND (t, 0) + && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == CALL_EXPR) + return TREE_OPERAND (TREE_OPERAND (t, 0), 1); + + return NULL_TREE; +} + + +/* Given an _EXPR TOP, reorganize all of the nested _EXPRs with the same + code so that they only appear as the second operand. This should only + be used for tree codes which are truly associative, such as + COMPOUND_EXPR and TRUTH_ANDIF_EXPR. Arithmetic is not associative + enough, due to the limited precision of arithmetic data types. + + This transformation is conservative; the operand 0 of a matching tree + node will only change if it is also a matching node. */ + +tree +right_assocify_expr (tree top) +{ + tree *p = ⊤ + enum tree_code code = TREE_CODE (*p); + while (TREE_CODE (*p) == code) + { + tree cur = *p; + tree lhs = TREE_OPERAND (cur, 0); + if (TREE_CODE (lhs) == code) + { + /* There's a left-recursion. If we have ((a, (b, c)), d), we + want to rearrange to (a, (b, (c, d))). */ + tree *q; + + /* Replace cur with the lhs; move (a, *) up. */ + *p = lhs; + + if (code == COMPOUND_EXPR) + { + /* We need to give (b, c) the type of c; previously lhs had + the type of b. */ + TREE_TYPE (lhs) = TREE_TYPE (cur); + if (TREE_SIDE_EFFECTS (cur)) + TREE_SIDE_EFFECTS (lhs) = 1; + } + + /* Walk through the op1 chain from there until we find something + with a different code. In this case, c. */ + for (q = &TREE_OPERAND (lhs, 1); TREE_CODE (*q) == code; + q = &TREE_OPERAND (*q, 1)) + TREE_TYPE (*q) = TREE_TYPE (cur); + + /* Change (*, d) into (c, d). */ + TREE_OPERAND (cur, 0) = *q; + + /* And plug it in where c used to be. */ + *q = cur; + } + else + p = &TREE_OPERAND (cur, 1); + } + return top; +} + +/* Normalize the statement TOP. If it is a COMPOUND_EXPR, reorganize it so + that we can traverse it without recursion. If it is null, replace it + with a nop. */ + +tree +rationalize_compound_expr (tree top) +{ + if (top == NULL_TREE) + top = build_empty_stmt (); + else if (TREE_CODE (top) == COMPOUND_EXPR) + top = right_assocify_expr (top); + + return top; +} + +/* Given a memory reference expression, return the base address. Note that, + in contrast with get_base_var, this will not recurse inside INDIRECT_REF + expressions. Therefore, given the reference PTR->FIELD, this function + will return *PTR. Whereas get_base_var would've returned PTR. */ + +tree +get_base_address (tree t) +{ + do + { + if (SSA_VAR_P (t) + || TREE_CODE (t) == INDIRECT_REF) + return t; + + switch (TREE_CODE (t)) + { + case ARRAY_REF: + case COMPONENT_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + case BIT_FIELD_REF: + t = TREE_OPERAND (t, 0); + break; + + default: + return NULL_TREE; + } + } + while (t); + + return t; +} + + +void +recalculate_side_effects (tree t) +{ + enum tree_code code = TREE_CODE (t); + int fro = first_rtl_op (code); + int i; + + switch (TREE_CODE_CLASS (code)) + { + case 'e': + switch (code) + { + case INIT_EXPR: + case MODIFY_EXPR: + case VA_ARG_EXPR: + case RTL_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + /* All of these have side-effects, no matter what their + operands are. */ + return; + + default: + break; + } + /* Fall through. */ + + case '<': /* a comparison expression */ + case '1': /* a unary arithmetic expression */ + case '2': /* a binary arithmetic expression */ + case 'r': /* a reference */ + TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); + for (i = 0; i < fro; ++i) + { + tree op = TREE_OPERAND (t, i); + if (op && TREE_SIDE_EFFECTS (op)) + TREE_SIDE_EFFECTS (t) = 1; + } + break; + } +} diff --git a/gcc/tree-gimple.h b/gcc/tree-gimple.h new file mode 100644 index 00000000000..d2c91032031 --- /dev/null +++ b/gcc/tree-gimple.h @@ -0,0 +1,127 @@ +/* Functions to analyze and validate GIMPLE trees. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. + Contributed by Diego Novillo + +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. */ + +#ifndef _TREE_SIMPLE_H +#define _TREE_SIMPLE_H 1 + + +#include "tree-iterator.h" + +extern tree create_tmp_var_raw (tree, const char *); +extern tree create_tmp_var (tree, const char *); +extern bool is_gimple_tmp_var (tree); +extern tree get_initialized_tmp_var (tree, tree *, tree *); +extern tree get_formal_tmp_var (tree, tree *); +extern void declare_tmp_vars (tree, tree); + +extern tree rationalize_compound_expr (tree); +extern tree right_assocify_expr (tree); +extern void annotate_all_with_locus (tree *, location_t); + +/* Validation of GIMPLE expressions. Note that these predicates only check + the basic form of the expression, they don't recurse to make sure that + underlying nodes are also of the right form. */ + +/* Returns true iff T is a valid GIMPLE statement. */ +bool is_gimple_stmt (tree); + +/* Returns true iff TYPE is a valid type for a scalar register variable. */ +bool is_gimple_reg_type (tree); +/* Returns true iff T is a scalar register variable. */ +bool is_gimple_reg (tree); +/* Returns true iff T is any sort of variable. */ +bool is_gimple_variable (tree); +/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */ +bool is_gimple_min_lval (tree); +/* Returns true iff T is an lvalue other than an INDIRECT_REF. */ +bool is_gimple_addr_expr_arg (tree); +/* Returns true iff T is any valid GIMPLE lvalue. */ +bool is_gimple_lvalue (tree); + +/* Returns true iff T is a GIMPLE restricted function invariant. */ +bool is_gimple_min_invariant (tree); +/* Returns true iff T is a GIMPLE rvalue. */ +bool is_gimple_val (tree); +/* Returns true iff T is a valid rhs for a MODIFY_EXPR. */ +bool is_gimple_rhs (tree); + +/* Returns true iff T is a valid if-statement condition. */ +bool is_gimple_condexpr (tree); + +/* Returns true iff T is a type conversion. */ +bool is_gimple_cast (tree); +/* Returns true iff T is a valid CONSTRUCTOR element (either an rvalue or + another CONSTRUCTOR). */ +bool is_gimple_constructor_elt (tree); +/* Returns true iff T is a variable that does not need to live in memory. */ +bool is_gimple_non_addressable (tree t); + +/* If T makes a function call, returns the CALL_EXPR operand. */ +tree get_call_expr_in (tree t); + +void recalculate_side_effects (tree); + +void append_to_statement_list (tree, tree *); +void append_to_statement_list_force (tree, tree *); +void append_to_compound_expr (tree, tree *); + +/* FIXME we should deduce this from the predicate. */ +typedef enum fallback_t { + fb_none = 0, + fb_rvalue = 1, + fb_lvalue = 2, + fb_mayfail = 4, + fb_either= fb_rvalue | fb_lvalue +} fallback_t; + +enum gimplify_status { + GS_ERROR = -2, /* Something Bad Seen. */ + GS_UNHANDLED = -1, /* A langhook result for "I dunno". */ + GS_OK = 0, /* We did something, maybe more to do. */ + GS_ALL_DONE = 1 /* The expression is fully gimplified. */ +}; + +enum gimplify_status gimplify_expr (tree *, tree *, tree *, + bool (*) (tree), fallback_t); +void gimplify_stmt (tree *); +void gimplify_to_stmt_list (tree *); +void gimplify_body (tree *, tree); +void push_gimplify_context (void); +void pop_gimplify_context (tree); + +/* Miscellaneous helpers. */ +tree get_base_address (tree t); +void gimple_add_tmp_var (tree); +tree gimple_current_bind_expr (void); +void gimple_push_bind_expr (tree); +void gimple_pop_bind_expr (void); +void unshare_all_trees (tree); +tree voidify_wrapper_expr (tree); +tree gimple_build_eh_filter (tree, tree, tree); +tree build_and_jump (tree *); +tree alloc_stmt_list (void); +void free_stmt_list (tree); +tree force_labels_r (tree *, int *, void *); + +/* In tree-nested.c. */ +extern void lower_nested_functions (tree); + +#endif /* _TREE_SIMPLE_H */ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index feb395f5c4b..cf50b9b18c2 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -46,7 +46,7 @@ Boston, MA 02111-1307, USA. */ /* I'm not real happy about this, but we need to handle gimple and non-gimple trees. */ #include "tree-iterator.h" -#include "tree-simple.h" +#include "tree-gimple.h" /* 0 if we should not perform inlining. 1 if we should expand functions calls inline at the tree level. diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c index 4e19142afd0..a569d0536b1 100644 --- a/gcc/tree-into-ssa.c +++ b/gcc/tree-into-ssa.c @@ -37,7 +37,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "bitmap.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "varray.h" #include "timevar.h" diff --git a/gcc/tree-iterator.c b/gcc/tree-iterator.c index 3f0eb5c9dc3..ebc477b68d0 100644 --- a/gcc/tree-iterator.c +++ b/gcc/tree-iterator.c @@ -23,7 +23,7 @@ Boston, MA 02111-1307, USA. */ #include "system.h" #include "coretypes.h" #include "tree.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-iterator.h" #include "ggc.h" diff --git a/gcc/tree-mudflap.c b/gcc/tree-mudflap.c index 9172541af39..474c7c45546 100644 --- a/gcc/tree-mudflap.c +++ b/gcc/tree-mudflap.c @@ -30,7 +30,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "flags.h" #include "function.h" #include "tree-inline.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-flow.h" #include "tree-mudflap.h" #include "tree-dump.h" diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index 7b92a75db30..1a00ff30f86 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -28,7 +28,7 @@ #include "function.h" #include "tree-dump.h" #include "tree-inline.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-iterator.h" #include "tree-flow.h" #include "cgraph.h" diff --git a/gcc/tree-nomudflap.c b/gcc/tree-nomudflap.c index 420fc39a88b..1e30194f77e 100644 --- a/gcc/tree-nomudflap.c +++ b/gcc/tree-nomudflap.c @@ -29,7 +29,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree-inline.h" #include "c-tree.h" #include "c-common.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "diagnostic.h" #include "hashtab.h" #include "output.h" diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index af5bf51f2ac..97b0b4a3e82 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -38,7 +38,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "bitmap.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "varray.h" #include "timevar.h" diff --git a/gcc/tree-simple.c b/gcc/tree-simple.c deleted file mode 100644 index 0215088deca..00000000000 --- a/gcc/tree-simple.c +++ /dev/null @@ -1,642 +0,0 @@ -/* Functions to analyze and validate GIMPLE trees. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. - Contributed by Diego Novillo - Rewritten by Jason Merrill - -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 "ggc.h" -#include "tm.h" -#include "tree.h" -#include "tree-simple.h" -#include "output.h" -#include "rtl.h" -#include "expr.h" -#include "bitmap.h" - -/* GCC GIMPLE structure - - Inspired by the SIMPLE C grammar at - - http://www-acaps.cs.mcgill.ca/info/McCAT/McCAT.html - - function: - FUNCTION_DECL - DECL_SAVED_TREE -> block - block: - BIND_EXPR - BIND_EXPR_VARS -> DECL chain - BIND_EXPR_BLOCK -> BLOCK - BIND_EXPR_BODY -> compound-stmt - compound-stmt: - COMPOUND_EXPR - op0 -> non-compound-stmt - op1 -> stmt - | EXPR_VEC - (or other alternate solution) - stmt: compound-stmt | non-compound-stmt - non-compound-stmt: - block - | if-stmt - | switch-stmt - | jump-stmt - | label-stmt - | try-stmt - | modify-stmt - | call-stmt - if-stmt: - COND_EXPR - op0 -> condition - op1 -> stmt - op2 -> stmt - switch-stmt: - SWITCH_EXPR - op0 -> val - op1 -> stmt - op2 -> array of case labels (as LABEL_DECLs?) - FIXME: add case value info - jump-stmt: - GOTO_EXPR - op0 -> LABEL_DECL | '*' ID - | RETURN_EXPR - op0 -> modify-stmt | NULL_TREE - (maybe -> RESULT_DECL | NULL_TREE? seems like some of expand_return - depends on getting a MODIFY_EXPR.) - | THROW_EXPR? do we need/want such a thing for opts, perhaps - to generate an ERT_THROW region? I think so. - Hmm...this would only work at the GIMPLE level, where we know that - the call args don't have any EH impact. Perhaps - annotation of the CALL_EXPR would work better. - | RESX_EXPR - label-stmt: - LABEL_EXPR - op0 -> LABEL_DECL - | CASE_LABEL_EXPR - CASE_LOW -> val | NULL_TREE - CASE_HIGH -> val | NULL_TREE - CASE_LABEL -> LABEL_DECL FIXME - try-stmt: - TRY_CATCH_EXPR - op0 -> stmt - op1 -> handler - | TRY_FINALLY_EXPR - op0 -> stmt - op1 -> stmt - handler: - catch-seq - | EH_FILTER_EXPR - | stmt - modify-stmt: - MODIFY_EXPR - op0 -> lhs - op1 -> rhs - call-stmt: CALL_EXPR - op0 -> ID | '&' ID - op1 -> arglist - - addr-expr-arg : compref | ID - lhs: addr-expr-arg | '*' ID | bitfieldref - min-lval: ID | '*' ID - bitfieldref : - BIT_FIELD_REF - op0 -> compref | min-lval - op1 -> CONST - op2 -> CONST - compref : - COMPONENT_REF - op0 -> compref | min-lval - | ARRAY_REF - op0 -> compref | min-lval - op1 -> val - | REALPART_EXPR - | IMAGPART_EXPR - - condition : val | val relop val - val : ID | CONST - - rhs : varname | CONST - | '*' ID - | '&' addr-expr-arg - | call_expr - | unop val - | val binop val - | '(' cast ')' val - - (cast here stands for all valid C typecasts) - - unop - : '+' - | '-' - | '!' - | '~' - - binop - : relop | '-' - | '+' - | '/' - | '*' - | '%' - | '&' - | '|' - | '<<' - | '>>' - | '^' - - relop - : '<' - | '<=' - | '>' - | '>=' - | '==' - | '!=' - -*/ - -static inline bool is_gimple_id (tree); - -/* Validation of GIMPLE expressions. */ - -/* Return nonzero if T is a GIMPLE RHS: - - rhs : varname | CONST - | '*' ID - | '&' varname_or_temp - | call_expr - | unop val - | val binop val - | '(' cast ')' val - | > - - The last option is only valid GIMPLE for vector and complex types; - aggregate types should have their constructors decomposed. */ - -bool -is_gimple_rhs (tree t) -{ - enum tree_code code = TREE_CODE (t); - - switch (TREE_CODE_CLASS (code)) - { - case '1': - case '2': - case '<': - return 1; - - default: - break; - } - - switch (code) - { - case TRUTH_NOT_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case ADDR_EXPR: - case CALL_EXPR: - case CONSTRUCTOR: - case COMPLEX_EXPR: - /* FIXME lower VA_ARG_EXPR. */ - case VA_ARG_EXPR: - case INTEGER_CST: - case REAL_CST: - case STRING_CST: - case COMPLEX_CST: - case VECTOR_CST: - return 1; - - default: - break; - } - - if (is_gimple_lvalue (t) || is_gimple_val (t)) - return 1; - - return 0; -} - -/* Returns nonzero if T is a valid CONSTRUCTOR component in GIMPLE, either - a val or another CONSTRUCTOR. */ - -bool -is_gimple_constructor_elt (tree t) -{ - return (is_gimple_val (t) - || TREE_CODE (t) == CONSTRUCTOR); -} - -/* Return nonzero if T is a valid LHS for a GIMPLE assignment expression. */ - -bool -is_gimple_lvalue (tree t) -{ - return (is_gimple_addr_expr_arg (t) - || TREE_CODE (t) == INDIRECT_REF - /* These are complex lvalues, but don't have addresses, so they - go here. */ - || TREE_CODE (t) == BIT_FIELD_REF); -} - - -/* Return nonzero if T is a GIMPLE condition: - - condexpr - : val - | val relop val */ - -bool -is_gimple_condexpr (tree t) -{ - return (is_gimple_val (t) - || TREE_CODE_CLASS (TREE_CODE (t)) == '<'); -} - - -/* Return nonzero if T is a valid operand for '&': - - varname - : arrayref - | compref - | ID */ - -bool -is_gimple_addr_expr_arg (tree t) -{ - return (is_gimple_id (t) - || TREE_CODE (t) == ARRAY_REF - || TREE_CODE (t) == COMPONENT_REF - || TREE_CODE (t) == REALPART_EXPR - || TREE_CODE (t) == IMAGPART_EXPR); -} - -/* Return nonzero if T is function invariant. Or rather a restricted - form of function invariant. */ - -bool -is_gimple_min_invariant (tree t) -{ - switch (TREE_CODE (t)) - { - case ADDR_EXPR: - return TREE_INVARIANT (t); - - case INTEGER_CST: - case REAL_CST: - case STRING_CST: - case COMPLEX_CST: - case VECTOR_CST: - return !TREE_OVERFLOW (t); - - default: - return false; - } -} - -/* Return nonzero if T looks like a valid GIMPLE statement. */ - -bool -is_gimple_stmt (tree t) -{ - enum tree_code code = TREE_CODE (t); - - if (IS_EMPTY_STMT (t)) - return 1; - - switch (code) - { - case BIND_EXPR: - case COND_EXPR: - /* These are only valid if they're void. */ - return VOID_TYPE_P (TREE_TYPE (t)); - - case SWITCH_EXPR: - case GOTO_EXPR: - case RETURN_EXPR: - case LABEL_EXPR: - case CASE_LABEL_EXPR: - case TRY_CATCH_EXPR: - case TRY_FINALLY_EXPR: - case EH_FILTER_EXPR: - case CATCH_EXPR: - case ASM_EXPR: - case RESX_EXPR: - case PHI_NODE: - case STATEMENT_LIST: - /* These are always void. */ - return 1; - - case VA_ARG_EXPR: - /* FIXME this should be lowered. */ - return 1; - - case COMPOUND_EXPR: - /* FIXME should we work harder to make COMPOUND_EXPRs void? */ - case CALL_EXPR: - case MODIFY_EXPR: - /* These are valid regardless of their type. */ - return 1; - - default: - return 0; - } -} - -/* Return nonzero if T is a variable. */ - -bool -is_gimple_variable (tree t) -{ - return (TREE_CODE (t) == VAR_DECL - || TREE_CODE (t) == PARM_DECL - || TREE_CODE (t) == RESULT_DECL - || TREE_CODE (t) == SSA_NAME); -} - -/* Return nonzero if T is a GIMPLE identifier (something with an address). */ - -static inline bool -is_gimple_id (tree t) -{ - return (is_gimple_variable (t) - || TREE_CODE (t) == FUNCTION_DECL - || TREE_CODE (t) == LABEL_DECL - /* Allow string constants, since they are addressable. */ - || TREE_CODE (t) == STRING_CST); -} - -/* Return nonzero if TYPE is a suitable type for a scalar register - variable. */ - -bool -is_gimple_reg_type (tree type) -{ - return (!AGGREGATE_TYPE_P (type) - && TREE_CODE (type) != COMPLEX_TYPE); -} - - -/* Return nonzero if T is a scalar register variable. */ - -bool -is_gimple_reg (tree t) -{ - if (TREE_CODE (t) == SSA_NAME) - t = SSA_NAME_VAR (t); - - return (is_gimple_variable (t) - && is_gimple_reg_type (TREE_TYPE (t)) - /* A volatile decl is not acceptable because we can't reuse it as - needed. We need to copy it into a temp first. */ - && ! TREE_THIS_VOLATILE (t) - && ! TREE_ADDRESSABLE (t) - && ! needs_to_live_in_memory (t)); -} - -/* Return nonzero if T is a GIMPLE variable whose address is not needed. */ - -bool -is_gimple_non_addressable (tree t) -{ - if (TREE_CODE (t) == SSA_NAME) - t = SSA_NAME_VAR (t); - - return (is_gimple_variable (t) - && ! TREE_ADDRESSABLE (t) - && ! needs_to_live_in_memory (t)); -} - -/* Return nonzero if T is a GIMPLE rvalue, i.e. an identifier or a - constant. */ - -bool -is_gimple_val (tree t) -{ - /* Make loads from volatiles and memory vars explicit. */ - if (is_gimple_variable (t) - && is_gimple_reg_type (TREE_TYPE (t)) - && !is_gimple_reg (t)) - return 0; - - /* FIXME make these decls. That can happen only when we expose the - entire landing-pad construct at the tree level. */ - if (TREE_CODE (t) == EXC_PTR_EXPR || TREE_CODE (t) == FILTER_EXPR) - return 1; - - return (is_gimple_variable (t) || is_gimple_min_invariant (t)); -} - - -/* Return true if T is a GIMPLE minimal lvalue, of the form - - min_lval: ID | '(' '*' ID ')' - - This never actually appears in the original SIMPLE grammar, but is - repeated in several places. */ - -bool -is_gimple_min_lval (tree t) -{ - return (is_gimple_id (t) - || TREE_CODE (t) == INDIRECT_REF); -} - -/* Return nonzero if T is a typecast operation of the form - '(' cast ')' val. */ - -bool -is_gimple_cast (tree t) -{ - return (TREE_CODE (t) == NOP_EXPR - || TREE_CODE (t) == CONVERT_EXPR - || TREE_CODE (t) == FIX_TRUNC_EXPR - || TREE_CODE (t) == FIX_CEIL_EXPR - || TREE_CODE (t) == FIX_FLOOR_EXPR - || TREE_CODE (t) == FIX_ROUND_EXPR); -} - - -/* If T makes a function call, return the corresponding CALL_EXPR operand. - Otherwise, return NULL_TREE. */ - -tree -get_call_expr_in (tree t) -{ - if (TREE_CODE (t) == CALL_EXPR) - return t; - else if (TREE_CODE (t) == MODIFY_EXPR - && TREE_CODE (TREE_OPERAND (t, 1)) == CALL_EXPR) - return TREE_OPERAND (t, 1); - else if (TREE_CODE (t) == RETURN_EXPR - && TREE_OPERAND (t, 0) - && TREE_CODE (TREE_OPERAND (t, 0)) == MODIFY_EXPR - && TREE_CODE (TREE_OPERAND (TREE_OPERAND (t, 0), 1)) == CALL_EXPR) - return TREE_OPERAND (TREE_OPERAND (t, 0), 1); - - return NULL_TREE; -} - - -/* Given an _EXPR TOP, reorganize all of the nested _EXPRs with the same - code so that they only appear as the second operand. This should only - be used for tree codes which are truly associative, such as - COMPOUND_EXPR and TRUTH_ANDIF_EXPR. Arithmetic is not associative - enough, due to the limited precision of arithmetic data types. - - This transformation is conservative; the operand 0 of a matching tree - node will only change if it is also a matching node. */ - -tree -right_assocify_expr (tree top) -{ - tree *p = ⊤ - enum tree_code code = TREE_CODE (*p); - while (TREE_CODE (*p) == code) - { - tree cur = *p; - tree lhs = TREE_OPERAND (cur, 0); - if (TREE_CODE (lhs) == code) - { - /* There's a left-recursion. If we have ((a, (b, c)), d), we - want to rearrange to (a, (b, (c, d))). */ - tree *q; - - /* Replace cur with the lhs; move (a, *) up. */ - *p = lhs; - - if (code == COMPOUND_EXPR) - { - /* We need to give (b, c) the type of c; previously lhs had - the type of b. */ - TREE_TYPE (lhs) = TREE_TYPE (cur); - if (TREE_SIDE_EFFECTS (cur)) - TREE_SIDE_EFFECTS (lhs) = 1; - } - - /* Walk through the op1 chain from there until we find something - with a different code. In this case, c. */ - for (q = &TREE_OPERAND (lhs, 1); TREE_CODE (*q) == code; - q = &TREE_OPERAND (*q, 1)) - TREE_TYPE (*q) = TREE_TYPE (cur); - - /* Change (*, d) into (c, d). */ - TREE_OPERAND (cur, 0) = *q; - - /* And plug it in where c used to be. */ - *q = cur; - } - else - p = &TREE_OPERAND (cur, 1); - } - return top; -} - -/* Normalize the statement TOP. If it is a COMPOUND_EXPR, reorganize it so - that we can traverse it without recursion. If it is null, replace it - with a nop. */ - -tree -rationalize_compound_expr (tree top) -{ - if (top == NULL_TREE) - top = build_empty_stmt (); - else if (TREE_CODE (top) == COMPOUND_EXPR) - top = right_assocify_expr (top); - - return top; -} - -/* Given a memory reference expression, return the base address. Note that, - in contrast with get_base_var, this will not recurse inside INDIRECT_REF - expressions. Therefore, given the reference PTR->FIELD, this function - will return *PTR. Whereas get_base_var would've returned PTR. */ - -tree -get_base_address (tree t) -{ - do - { - if (SSA_VAR_P (t) - || TREE_CODE (t) == INDIRECT_REF) - return t; - - switch (TREE_CODE (t)) - { - case ARRAY_REF: - case COMPONENT_REF: - case REALPART_EXPR: - case IMAGPART_EXPR: - case BIT_FIELD_REF: - t = TREE_OPERAND (t, 0); - break; - - default: - return NULL_TREE; - } - } - while (t); - - return t; -} - - -void -recalculate_side_effects (tree t) -{ - enum tree_code code = TREE_CODE (t); - int fro = first_rtl_op (code); - int i; - - switch (TREE_CODE_CLASS (code)) - { - case 'e': - switch (code) - { - case INIT_EXPR: - case MODIFY_EXPR: - case VA_ARG_EXPR: - case RTL_EXPR: - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - /* All of these have side-effects, no matter what their - operands are. */ - return; - - default: - break; - } - /* Fall through. */ - - case '<': /* a comparison expression */ - case '1': /* a unary arithmetic expression */ - case '2': /* a binary arithmetic expression */ - case 'r': /* a reference */ - TREE_SIDE_EFFECTS (t) = TREE_THIS_VOLATILE (t); - for (i = 0; i < fro; ++i) - { - tree op = TREE_OPERAND (t, i); - if (op && TREE_SIDE_EFFECTS (op)) - TREE_SIDE_EFFECTS (t) = 1; - } - break; - } -} diff --git a/gcc/tree-simple.h b/gcc/tree-simple.h deleted file mode 100644 index d2c91032031..00000000000 --- a/gcc/tree-simple.h +++ /dev/null @@ -1,127 +0,0 @@ -/* Functions to analyze and validate GIMPLE trees. - Copyright (C) 2002, 2003 Free Software Foundation, Inc. - Contributed by Diego Novillo - -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. */ - -#ifndef _TREE_SIMPLE_H -#define _TREE_SIMPLE_H 1 - - -#include "tree-iterator.h" - -extern tree create_tmp_var_raw (tree, const char *); -extern tree create_tmp_var (tree, const char *); -extern bool is_gimple_tmp_var (tree); -extern tree get_initialized_tmp_var (tree, tree *, tree *); -extern tree get_formal_tmp_var (tree, tree *); -extern void declare_tmp_vars (tree, tree); - -extern tree rationalize_compound_expr (tree); -extern tree right_assocify_expr (tree); -extern void annotate_all_with_locus (tree *, location_t); - -/* Validation of GIMPLE expressions. Note that these predicates only check - the basic form of the expression, they don't recurse to make sure that - underlying nodes are also of the right form. */ - -/* Returns true iff T is a valid GIMPLE statement. */ -bool is_gimple_stmt (tree); - -/* Returns true iff TYPE is a valid type for a scalar register variable. */ -bool is_gimple_reg_type (tree); -/* Returns true iff T is a scalar register variable. */ -bool is_gimple_reg (tree); -/* Returns true iff T is any sort of variable. */ -bool is_gimple_variable (tree); -/* Returns true iff T is a variable or an INDIRECT_REF (of a variable). */ -bool is_gimple_min_lval (tree); -/* Returns true iff T is an lvalue other than an INDIRECT_REF. */ -bool is_gimple_addr_expr_arg (tree); -/* Returns true iff T is any valid GIMPLE lvalue. */ -bool is_gimple_lvalue (tree); - -/* Returns true iff T is a GIMPLE restricted function invariant. */ -bool is_gimple_min_invariant (tree); -/* Returns true iff T is a GIMPLE rvalue. */ -bool is_gimple_val (tree); -/* Returns true iff T is a valid rhs for a MODIFY_EXPR. */ -bool is_gimple_rhs (tree); - -/* Returns true iff T is a valid if-statement condition. */ -bool is_gimple_condexpr (tree); - -/* Returns true iff T is a type conversion. */ -bool is_gimple_cast (tree); -/* Returns true iff T is a valid CONSTRUCTOR element (either an rvalue or - another CONSTRUCTOR). */ -bool is_gimple_constructor_elt (tree); -/* Returns true iff T is a variable that does not need to live in memory. */ -bool is_gimple_non_addressable (tree t); - -/* If T makes a function call, returns the CALL_EXPR operand. */ -tree get_call_expr_in (tree t); - -void recalculate_side_effects (tree); - -void append_to_statement_list (tree, tree *); -void append_to_statement_list_force (tree, tree *); -void append_to_compound_expr (tree, tree *); - -/* FIXME we should deduce this from the predicate. */ -typedef enum fallback_t { - fb_none = 0, - fb_rvalue = 1, - fb_lvalue = 2, - fb_mayfail = 4, - fb_either= fb_rvalue | fb_lvalue -} fallback_t; - -enum gimplify_status { - GS_ERROR = -2, /* Something Bad Seen. */ - GS_UNHANDLED = -1, /* A langhook result for "I dunno". */ - GS_OK = 0, /* We did something, maybe more to do. */ - GS_ALL_DONE = 1 /* The expression is fully gimplified. */ -}; - -enum gimplify_status gimplify_expr (tree *, tree *, tree *, - bool (*) (tree), fallback_t); -void gimplify_stmt (tree *); -void gimplify_to_stmt_list (tree *); -void gimplify_body (tree *, tree); -void push_gimplify_context (void); -void pop_gimplify_context (tree); - -/* Miscellaneous helpers. */ -tree get_base_address (tree t); -void gimple_add_tmp_var (tree); -tree gimple_current_bind_expr (void); -void gimple_push_bind_expr (tree); -void gimple_pop_bind_expr (void); -void unshare_all_trees (tree); -tree voidify_wrapper_expr (tree); -tree gimple_build_eh_filter (tree, tree, tree); -tree build_and_jump (tree *); -tree alloc_stmt_list (void); -void free_stmt_list (tree); -tree force_labels_r (tree *, int *, void *); - -/* In tree-nested.c. */ -extern void lower_nested_functions (tree); - -#endif /* _TREE_SIMPLE_H */ diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c index 2131d0047f2..d447b82d768 100644 --- a/gcc/tree-sra.c +++ b/gcc/tree-sra.c @@ -38,7 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "langhooks.h" #include "tree-inline.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-dump.h" #include "tree-pass.h" #include "timevar.h" diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 02eb5139698..2bcb4efec9b 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -36,7 +36,7 @@ Boston, MA 02111-1307, USA. */ #include "function.h" #include "diagnostic.h" #include "tree-dump.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-flow.h" #include "tree-inline.h" #include "tree-alias-common.h" diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index ef655629abd..bb7939cd10c 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -51,7 +51,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "diagnostic.h" #include "tree-inline.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-dump.h" #include "tree-pass.h" #include "timevar.h" diff --git a/gcc/tree-ssa-copyrename.c b/gcc/tree-ssa-copyrename.c index 91c0f74ac55..dd698835f06 100644 --- a/gcc/tree-ssa-copyrename.c +++ b/gcc/tree-ssa-copyrename.c @@ -30,7 +30,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "bitmap.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "timevar.h" #include "tree-alias-common.h" diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index c8ff7eb9d98..7921a9f0cf6 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -59,7 +59,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tree.h" #include "diagnostic.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-dump.h" #include "tree-pass.h" #include "timevar.h" diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c index aedcbc1e397..28c3d578581 100644 --- a/gcc/tree-ssa-live.c +++ b/gcc/tree-ssa-live.c @@ -30,7 +30,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "bitmap.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "varray.h" #include "timevar.h" diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c index 76a9a56c7e2..c249441dd7c 100644 --- a/gcc/tree-ssa-pre.c +++ b/gcc/tree-ssa-pre.c @@ -34,7 +34,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "tree-inline.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-dump.h" #include "timevar.h" #include "fibheap.h" diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 58d44c2d5e6..8ecce07e4f4 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -37,7 +37,7 @@ Boston, MA 02111-1307, USA. */ #include "diagnostic.h" #include "bitmap.h" #include "tree-flow.h" -#include "tree-simple.h" +#include "tree-gimple.h" #include "tree-inline.h" #include "varray.h" #include "timevar.h"