X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgimple-low.c;h=ff6b8b27f30cf79d94ccc57266fd05e198eb077f;hb=13774f7b28a842c75a76bb2f08c448fca3bb9ca5;hp=5544a18468dff65ebdd5c12a985bbde31c7601cc;hpb=0f9005ddc07f0919938a893f0fb526b68783c72c;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 5544a18468d..ff6b8b27f30 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -1,6 +1,6 @@ /* Tree lowering pass. Lowers GIMPLE into unstructured form. - Copyright (C) 2003 Free Software Foundation, Inc. + Copyright (C) 2003, 2005 Free Software Foundation, Inc. This file is part of GCC. @@ -16,8 +16,8 @@ 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. */ +Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ #include "config.h" #include "system.h" @@ -25,7 +25,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm.h" #include "tree.h" #include "rtl.h" -#include "errors.h" #include "varray.h" #include "tree-gimple.h" #include "tree-inline.h" @@ -56,11 +55,10 @@ static void lower_stmt (tree_stmt_iterator *, struct lower_data *); static void lower_bind_expr (tree_stmt_iterator *, struct lower_data *); static void lower_cond_expr (tree_stmt_iterator *, struct lower_data *); static void lower_return_expr (tree_stmt_iterator *, struct lower_data *); -static bool expand_var_p (tree); /* Lowers the body of current_function_decl. */ -static void +static unsigned int lower_function_body (void) { struct lower_data data; @@ -69,16 +67,14 @@ lower_function_body (void) tree_stmt_iterator i; tree t, x; - if (TREE_CODE (bind) != BIND_EXPR) - abort (); + gcc_assert (TREE_CODE (bind) == BIND_EXPR); + memset (&data, 0, sizeof (data)); data.block = DECL_INITIAL (current_function_decl); BLOCK_SUBBLOCKS (data.block) = NULL_TREE; BLOCK_CHAIN (data.block) = NULL_TREE; TREE_ASM_WRITTEN (data.block) = 1; - data.return_statements = NULL_TREE; - *body_p = alloc_stmt_list (); i = tsi_start (*body_p); tsi_link_after (&i, bind, TSI_NEW_STMT); @@ -93,7 +89,7 @@ lower_function_body (void) && (data.return_statements == NULL || TREE_OPERAND (TREE_VALUE (data.return_statements), 0) != NULL)) { - x = build (RETURN_EXPR, void_type_node, NULL); + x = build1 (RETURN_EXPR, void_type_node, NULL); SET_EXPR_LOCATION (x, cfun->function_end_locus); tsi_link_after (&i, x, TSI_CONTINUE_LINKING); } @@ -102,7 +98,7 @@ lower_function_body (void) at the end of the function. */ for (t = data.return_statements ; t ; t = TREE_CHAIN (t)) { - x = build (LABEL_EXPR, void_type_node, TREE_PURPOSE (t)); + x = build1 (LABEL_EXPR, void_type_node, TREE_PURPOSE (t)); tsi_link_after (&i, x, TSI_CONTINUE_LINKING); /* Remove the line number from the representative return statement. @@ -117,12 +113,12 @@ lower_function_body (void) tsi_link_after (&i, x, TSI_CONTINUE_LINKING); } - if (data.block != DECL_INITIAL (current_function_decl)) - abort (); + gcc_assert (data.block == DECL_INITIAL (current_function_decl)); BLOCK_SUBBLOCKS (data.block) = blocks_nreverse (BLOCK_SUBBLOCKS (data.block)); clear_block_marks (data.block); + return 0; } struct tree_opt_pass pass_lower_cf = @@ -136,7 +132,7 @@ struct tree_opt_pass pass_lower_cf = 0, /* tv_id */ PROP_gimple_any, /* properties_required */ PROP_gimple_lcf, /* properties_provided */ - PROP_gimple_any, /* properties_destroyed */ + 0, /* properties_destroyed */ 0, /* todo_flags_start */ TODO_dump_func, /* todo_flags_finish */ 0 /* letter */ @@ -147,7 +143,7 @@ struct tree_opt_pass pass_lower_cf = when they are changed -- if this has to be done, the lowering routine must do it explicitly. DATA is passed through the recursion. */ -void +static void lower_stmt_body (tree expr, struct lower_data *data) { tree_stmt_iterator tsi; @@ -156,6 +152,25 @@ lower_stmt_body (tree expr, struct lower_data *data) lower_stmt (&tsi, data); } + +/* Lower the OpenMP directive statement pointed by TSI. DATA is + passed through the recursion. */ + +static void +lower_omp_directive (tree_stmt_iterator *tsi, struct lower_data *data) +{ + tree stmt; + + stmt = tsi_stmt (*tsi); + + lower_stmt_body (OMP_BODY (stmt), data); + tsi_link_before (tsi, stmt, TSI_SAME_STMT); + tsi_link_before (tsi, OMP_BODY (stmt), TSI_SAME_STMT); + OMP_BODY (stmt) = NULL_TREE; + tsi_delink (tsi); +} + + /* Lowers statement TSI. DATA is passed through the recursion. */ static void @@ -197,12 +212,23 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data) case GOTO_EXPR: case LABEL_EXPR: case SWITCH_EXPR: + case OMP_FOR: + case OMP_SECTIONS: + case OMP_SECTION: + case OMP_SINGLE: + case OMP_MASTER: + case OMP_ORDERED: + case OMP_CRITICAL: + case OMP_RETURN: + case OMP_CONTINUE: break; + case OMP_PARALLEL: + lower_omp_directive (tsi, data); + return; + default: - print_node_brief (stderr, "", stmt, 0); - case COMPOUND_EXPR: - abort (); + gcc_unreachable (); } tsi_next (tsi); @@ -224,15 +250,13 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) /* The outermost block of the original function may not be the outermost statement chain of the gimplified function. So we may see the outermost block just inside the function. */ - if (new_block != DECL_INITIAL (current_function_decl)) - abort (); + gcc_assert (new_block == DECL_INITIAL (current_function_decl)); new_block = NULL; } else { /* We do not expect to handle duplicate blocks. */ - if (TREE_ASM_WRITTEN (new_block)) - abort (); + gcc_assert (!TREE_ASM_WRITTEN (new_block)); TREE_ASM_WRITTEN (new_block) = 1; /* Block tree may get clobbered by inlining. Normally this would @@ -252,8 +276,7 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) if (new_block) { - if (data->block != new_block) - abort (); + gcc_assert (data->block == new_block); BLOCK_SUBBLOCKS (new_block) = blocks_nreverse (BLOCK_SUBBLOCKS (new_block)); @@ -265,6 +288,54 @@ lower_bind_expr (tree_stmt_iterator *tsi, struct lower_data *data) tsi_delink (tsi); } +/* Try to determine whether a TRY_CATCH expression can fall through. + This is a subroutine of block_may_fallthru. */ + +static bool +try_catch_may_fallthru (tree stmt) +{ + tree_stmt_iterator i; + + /* If the TRY block can fall through, the whole TRY_CATCH can + fall through. */ + if (block_may_fallthru (TREE_OPERAND (stmt, 0))) + return true; + + i = tsi_start (TREE_OPERAND (stmt, 1)); + switch (TREE_CODE (tsi_stmt (i))) + { + case CATCH_EXPR: + /* We expect to see a sequence of CATCH_EXPR trees, each with a + catch expression and a body. The whole TRY_CATCH may fall + through iff any of the catch bodies falls through. */ + for (; !tsi_end_p (i); tsi_next (&i)) + { + if (block_may_fallthru (CATCH_BODY (tsi_stmt (i)))) + return true; + } + return false; + + case EH_FILTER_EXPR: + /* The exception filter expression only matters if there is an + exception. If the exception does not match EH_FILTER_TYPES, + we will execute EH_FILTER_FAILURE, and we will fall through + if that falls through. If the exception does match + EH_FILTER_TYPES, the stack unwinder will continue up the + stack, so we will not fall through. We don't know whether we + will throw an exception which matches EH_FILTER_TYPES or not, + so we just ignore EH_FILTER_TYPES and assume that we might + throw an exception which doesn't match. */ + return block_may_fallthru (EH_FILTER_FAILURE (tsi_stmt (i))); + + default: + /* This case represents statements to be executed when an + exception occurs. Those statements are implicitly followed + by a RESX_EXPR to resume execution after the exception. So + in this case the TRY_CATCH never falls through. */ + return false; + } +} + /* Try to determine if we can fall out of the bottom of BLOCK. This guess need not be 100% accurate; simply be conservative and return true if we don't know. This is used only to avoid stupidly generating extra code. @@ -280,11 +351,17 @@ block_may_fallthru (tree block) case GOTO_EXPR: case RETURN_EXPR: case RESX_EXPR: - case SWITCH_EXPR: /* Easy cases. If the last statement of the block implies control transfer, then we can't fall through. */ return false; + case SWITCH_EXPR: + /* If SWITCH_LABELS is set, this is lowered, and represents a + branch to a selected label and hence can not fall through. + Otherwise SWITCH_BODY is set, and the switch can fall + through. */ + return SWITCH_LABELS (stmt) == NULL_TREE; + case COND_EXPR: if (block_may_fallthru (COND_EXPR_THEN (stmt))) return true; @@ -293,8 +370,19 @@ block_may_fallthru (tree block) case BIND_EXPR: return block_may_fallthru (BIND_EXPR_BODY (stmt)); + case TRY_CATCH_EXPR: + return try_catch_may_fallthru (stmt); + case TRY_FINALLY_EXPR: - return block_may_fallthru (TREE_OPERAND (stmt, 1)); + /* The finally clause is always executed after the try clause, + so if it does not fall through, then the try-finally will not + fall through. Otherwise, if the try clause does not fall + through, then when the finally clause falls through it will + resume execution wherever the try clause was going. So the + whole try-finally will only fall through if both the try + clause and the finally clause fall through. */ + return (block_may_fallthru (TREE_OPERAND (stmt, 0)) + && block_may_fallthru (TREE_OPERAND (stmt, 1))); case MODIFY_EXPR: if (TREE_CODE (TREE_OPERAND (stmt, 1)) == CALL_EXPR) @@ -306,6 +394,9 @@ block_may_fallthru (tree block) case CALL_EXPR: /* Functions that do not return do not fall through. */ return (call_expr_flags (stmt) & ECF_NORETURN) == 0; + + case CLEANUP_POINT_EXPR: + return block_may_fallthru (TREE_OPERAND (stmt, 0)); default: return true; @@ -438,99 +529,98 @@ lower_return_expr (tree_stmt_iterator *tsi, struct lower_data *data) /* Generate a goto statement and remove the return statement. */ found: - t = build (GOTO_EXPR, void_type_node, label); + t = build1 (GOTO_EXPR, void_type_node, label); SET_EXPR_LOCUS (t, EXPR_LOCUS (stmt)); tsi_link_before (tsi, t, TSI_SAME_STMT); tsi_delink (tsi); } -/* Record the variables in VARS. */ +/* Record the variables in VARS into function FN. */ void -record_vars (tree vars) +record_vars_into (tree vars, tree fn) { + struct function *saved_cfun = cfun; + + if (fn != current_function_decl) + cfun = DECL_STRUCT_FUNCTION (fn); + for (; vars; vars = TREE_CHAIN (vars)) { tree var = vars; + /* BIND_EXPRs contains also function/type/constant declarations + we don't need to care about. */ + if (TREE_CODE (var) != VAR_DECL) + continue; + /* Nothing to do in this case. */ if (DECL_EXTERNAL (var)) continue; - if (TREE_CODE (var) == FUNCTION_DECL) - continue; /* Record the variable. */ cfun->unexpanded_var_list = tree_cons (NULL_TREE, var, cfun->unexpanded_var_list); } -} - -/* Check whether to expand a variable VAR. */ - -static bool -expand_var_p (tree var) -{ - struct var_ann_d *ann; - if (TREE_CODE (var) != VAR_DECL) - return true; + if (fn != current_function_decl) + cfun = saved_cfun; +} - /* Leave statics and externals alone. */ - if (TREE_STATIC (var) || DECL_EXTERNAL (var)) - return true; - /* Remove all unused local variables. */ - ann = var_ann (var); - if (!ann || !ann->used) - return false; +/* Record the variables in VARS into current_function_decl. */ - return true; +void +record_vars (tree vars) +{ + record_vars_into (vars, current_function_decl); } -/* Throw away variables that are unused. */ + +/* Mark BLOCK used if it has a used variable in it, then recurse over its + subblocks. */ static void -remove_useless_vars (void) +mark_blocks_with_used_vars (tree block) { - tree var, *cell; - FILE *df = NULL; + tree var; + tree subblock; - if (dump_file && (dump_flags & TDF_DETAILS)) + if (!TREE_USED (block)) { - df = dump_file; - fputs ("Discarding as unused:\n", df); - } - - for (cell = &cfun->unexpanded_var_list; *cell; ) - { - var = TREE_VALUE (*cell); - - if (!expand_var_p (var)) + for (var = BLOCK_VARS (block); + var; + var = TREE_CHAIN (var)) { - if (df) + if (TREE_USED (var)) { - fputs (" ", df); - print_generic_expr (df, var, dump_flags); - fputc ('\n', df); + TREE_USED (block) = true; + break; } - - *cell = TREE_CHAIN (*cell); - continue; } - - cell = &TREE_CHAIN (*cell); } + for (subblock = BLOCK_SUBBLOCKS (block); + subblock; + subblock = BLOCK_CHAIN (subblock)) + mark_blocks_with_used_vars (subblock); +} - if (df) - fputc ('\n', df); +/* Mark the used attribute on blocks correctly. */ + +static unsigned int +mark_used_blocks (void) +{ + mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl)); + return 0; } -struct tree_opt_pass pass_remove_useless_vars = + +struct tree_opt_pass pass_mark_used_blocks = { - "vars", /* name */ + "blocks", /* name */ NULL, /* gate */ - remove_useless_vars, /* execute */ + mark_used_blocks, /* execute */ NULL, /* sub */ NULL, /* next */ 0, /* static_pass_number */