X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-gimplify.c;h=e50050c2324cff5e7a71792e95a49b4c2b804add;hb=fc7a207afb278ff786674fe38579828f382765bf;hp=f20ddfe39050c86d4faa14f48c44862c157718a8;hpb=0bed386979f6bdc139c519bab996bed698ade995;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c index f20ddfe3905..e50050c2324 100644 --- a/gcc/c-gimplify.c +++ b/gcc/c-gimplify.c @@ -2,7 +2,8 @@ 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. + Copyright (C) 2002, 2003, 2004, 2005, 2007, 2008 + 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 @@ -11,7 +12,7 @@ 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 +Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY @@ -20,20 +21,18 @@ 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. */ +along with GCC; see the file COPYING3. If not see +. */ #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 "gimple.h" #include "hard-reg-set.h" #include "basic-block.h" #include "tree-flow.h" @@ -70,61 +69,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA 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 @@ -133,229 +77,51 @@ pop_context (void) void c_genericize (tree fndecl) { - FILE *dump_file; + FILE *dump_orig; 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) + dump_orig = dump_begin (TDI_original, &local_dump_flags); + if (dump_orig) { - fprintf (dump_file, "\n;; Function %s", + fprintf (dump_orig, "\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"); + fprintf (dump_orig, " (%s)\n", + (!DECL_ASSEMBLER_NAME_SET_P (fndecl) ? "null" + : IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (fndecl)))); + fprintf (dump_orig, ";; enabled by -%s\n", dump_flag_name (TDI_original)); + fprintf (dump_orig, "\n"); if (local_dump_flags & TDF_RAW) dump_node (DECL_SAVED_TREE (fndecl), - TDF_SLIM | local_dump_flags, dump_file); + TDF_SLIM | local_dump_flags, dump_orig); else - print_c_tree (dump_file, DECL_SAVED_TREE (fndecl)); - fprintf (dump_file, "\n"); + print_c_tree (dump_orig, DECL_SAVED_TREE (fndecl)); + fprintf (dump_orig, "\n"); - dump_end (TDI_original, dump_file); + dump_end (TDI_original, dump_orig); } - /* 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. */ + /* Dump all nested functions now. */ 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) { + unsigned i; tree enclosing; + gimple bind; + VEC(gimple, heap) *stack = gimple_bind_expr_stack (); - for (enclosing = gimple_current_bind_expr (); - enclosing; enclosing = TREE_CHAIN (enclosing)) - if (BIND_EXPR_BLOCK (enclosing)) + for (i = 0; VEC_iterate (gimple, stack, i, bind); i++) + if (gimple_bind_block (bind)) break; - enclosing = BIND_EXPR_BLOCK (enclosing); + enclosing = gimple_bind_block (bind); BLOCK_SUBBLOCKS (enclosing) = chainon (BLOCK_SUBBLOCKS (enclosing), block); } @@ -366,8 +132,8 @@ add_block_to_enclosing (tree 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 +c_build_bind_expr (location_t loc, tree block, tree body) { tree decls, bind; @@ -389,714 +155,40 @@ c_build_bind_expr (tree block, tree body) } 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) + body = build_empty_stmt (loc); + if (decls || block) { - /* 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); + bind = build3 (BIND_EXPR, void_type_node, decls, body, block); + TREE_SIDE_EFFECTS (bind) = 1; + SET_EXPR_LOCATION (bind, loc); } 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. + bind = body; - 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; + return bind; } /* 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. */ +/* Do C-specific gimplification on *EXPR_P. PRE_P and POST_P are as in + gimplify_expr. */ int -c_gimplify_expr (tree *expr_p, tree *pre_p ATTRIBUTE_UNUSED, - tree *post_p ATTRIBUTE_UNUSED) +c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED, + gimple_seq *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); + /* This is handled mostly by gimplify.c, but we have to deal with + not warning about int x = x; as it is a GCC extension to turn off + this warning but only if warn_init_self is zero. */ + if (code == DECL_EXPR + && TREE_CODE (DECL_EXPR_DECL (*expr_p)) == VAR_DECL + && !DECL_EXTERNAL (DECL_EXPR_DECL (*expr_p)) + && !TREE_STATIC (DECL_EXPR_DECL (*expr_p)) + && (DECL_INITIAL (DECL_EXPR_DECL (*expr_p)) == DECL_EXPR_DECL (*expr_p)) + && !warn_init_self) + TREE_NO_WARNING (DECL_EXPR_DECL (*expr_p)) = 1; - /* 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)))); + return GS_UNHANDLED; } -#endif