X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fc-gimplify.c;h=404ea71f0fcd6c5bdf699daf2494844d28d195a2;hb=5d4b6e9c06cae8242813f303f804f31222500c65;hp=2e9b4b92b640096353635d500a63fc134ffeef96;hpb=eaae3b7592d5ecb2b2d6def2f85573fe41bb71c5;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c index 2e9b4b92b64..404ea71f0fc 100644 --- a/gcc/c-gimplify.c +++ b/gcc/c-gimplify.c @@ -2,7 +2,7 @@ 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 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 @@ -72,26 +72,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA /* 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_compound_literal_expr (tree *); -static void gimplify_cleanup_stmts (tree); -static tree gimplify_c_loop (tree, tree, tree, bool); -static void push_context (void); -static void pop_context (void); -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 { @@ -154,7 +135,6 @@ c_genericize (tree fndecl) /* Go ahead and gimplify for now. */ push_context (); - gimplify_cleanup_stmts (fndecl); gimplify_function_tree (fndecl); pop_context (); @@ -169,151 +149,6 @@ c_genericize (tree fndecl) c_genericize (cgn->decl); } -/* Genericize a CLEANUP_STMT. This just turns into a TRY_FINALLY or - TRY_CATCH depending on whether it's EH-only. */ - -static tree -gimplify_cleanup_stmt (tree *stmt_p, int *walk_subtrees, - void *data ATTRIBUTE_UNUSED) -{ - tree stmt = *stmt_p; - - if (DECL_P (stmt) || TYPE_P (stmt)) - *walk_subtrees = 0; - else if (TREE_CODE (stmt) == CLEANUP_STMT) - *stmt_p = build (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR, - void_type_node, CLEANUP_BODY (stmt), CLEANUP_EXPR (stmt)); - - return NULL; -} - -static void -gimplify_cleanup_stmts (tree fndecl) -{ - walk_tree (&DECL_SAVED_TREE (fndecl), gimplify_cleanup_stmt, NULL, NULL); -} - -/* 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 = *stmt_p; - tree pre, post; - int saved_stmts_are_full_exprs_p; - location_t stmt_locus; - enum gimplify_status ret; - - /* 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 */ - - /* 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; - - switch (TREE_CODE (stmt)) - { - case COMPOUND_STMT: - stmt = COMPOUND_BODY (stmt); - ret = GS_OK; - break; - - case FOR_STMT: - ret = gimplify_for_stmt (&stmt, &pre); - 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 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; - - default: - if (lang_gimplify_stmt && (*lang_gimplify_stmt) (&stmt)) - { - 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); - cont: - /* Restore saved state. */ - current_stmt_tree ()->stmts_are_full_exprs_p = saved_stmts_are_full_exprs_p; - *stmt_p = pre; - - return GS_ALL_DONE; -} - static void add_block_to_enclosing (tree block) { @@ -361,7 +196,7 @@ c_build_bind_expr (tree block, tree body) body = build_empty_stmt (); if (decls || block) { - bind = build (BIND_EXPR, void_type_node, decls, body, block); + bind = build3 (BIND_EXPR, void_type_node, decls, body, block); TREE_SIDE_EFFECTS (bind) = 1; } else @@ -404,41 +239,17 @@ gimplify_expr_stmt (tree *stmt_p) 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); - } + warn_if_unused_value (stmt, input_location); } 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 = alloc_stmt_list (); *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); - 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. @@ -553,9 +364,8 @@ gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) 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 = build3 (COND_EXPR, void_type_node, cond, exit, t); exit = fold (exit); gimplify_stmt (&exit); } @@ -566,8 +376,6 @@ gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first) 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); @@ -603,10 +411,8 @@ gimplify_for_stmt (tree *stmt_p, tree *pre_p) tree stmt = *stmt_p; if (FOR_INIT_STMT (stmt)) - { - gimplify_stmt (&FOR_INIT_STMT (stmt)); - append_to_statement_list (FOR_INIT_STMT (stmt), pre_p); - } + gimplify_and_add (FOR_INIT_STMT (stmt), pre_p); + *stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt), FOR_EXPR (stmt), 1); @@ -635,29 +441,6 @@ gimplify_do_stmt (tree *stmt_p) 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; - 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; - - return GS_OK; -} - /* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */ static enum gimplify_status @@ -669,133 +452,30 @@ gimplify_switch_stmt (tree *stmt_p) 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); + *stmt_p = build3 (SWITCH_EXPR, SWITCH_TYPE (stmt), SWITCH_COND (stmt), + body, NULL_TREE); + SET_EXPR_LOCATION (*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 *STMT_P by making any necessary allocation - and initialization explicit. */ - -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 + DECL_EXPR before the current EXPR_STMT and using its anonymous decl instead. */ static enum gimplify_status -gimplify_compound_literal_expr (tree *expr_p) +gimplify_compound_literal_expr (tree *expr_p, tree *pre_p) { tree decl_s = COMPOUND_LITERAL_EXPR_DECL_STMT (*expr_p); - tree decl = DECL_STMT_DECL (decl_s); + tree decl = DECL_EXPR_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 @@ -803,26 +483,58 @@ gimplify_compound_literal_expr (tree *expr_p) if (DECL_NAME (decl) == NULL_TREE) gimple_add_tmp_var (decl); - gimplify_decl_stmt (&decl_s); - *expr_p = decl_s ? decl_s : decl; + gimplify_and_add (decl_s, pre_p); + *expr_p = 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) +c_gimplify_expr (tree *expr_p, tree *pre_p, 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 DECL_EXPR: + /* 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 (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; + return GS_UNHANDLED; + case COMPOUND_LITERAL_EXPR: - return gimplify_compound_literal_expr (expr_p); + return gimplify_compound_literal_expr (expr_p, pre_p); + + case FOR_STMT: + return gimplify_for_stmt (expr_p, pre_p); + + case WHILE_STMT: + return gimplify_while_stmt (expr_p); + + case DO_STMT: + return gimplify_do_stmt (expr_p); + + case SWITCH_STMT: + return gimplify_switch_stmt (expr_p); + + case EXPR_STMT: + return gimplify_expr_stmt (expr_p); + + case CONTINUE_STMT: + *expr_p = build_bc_goto (bc_continue); + return GS_ALL_DONE; + + case BREAK_STMT: + *expr_p = build_bc_goto (bc_break); + return GS_ALL_DONE; default: return GS_UNHANDLED;