X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgimple-low.c;h=4f814a5e6d7e0d3722e6563565152727d907fdba;hb=9d099e65af650af4352e3b97555ca5b60a7574f3;hp=c6f6f7611e2a39792feeada69e5573026adc92ef;hpb=0d59b19dc2331e2fd6d3ce1d95d0d6c22263c282;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index c6f6f7611e2..4f814a5e6d7 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. @@ -145,7 +145,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; @@ -263,6 +263,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. @@ -278,11 +326,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; @@ -291,8 +345,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) @@ -540,3 +605,57 @@ struct tree_opt_pass pass_remove_useless_vars = TODO_dump_func, /* todo_flags_finish */ 0 /* letter */ }; + +/* Mark BLOCK used if it has a used variable in it, then recurse over its + subblocks. */ + +static void +mark_blocks_with_used_vars (tree block) +{ + tree var; + tree subblock; + + if (!TREE_USED (block)) + { + for (var = BLOCK_VARS (block); + var; + var = TREE_CHAIN (var)) + { + if (TREE_USED (var)) + { + TREE_USED (block) = true; + break; + } + } + } + for (subblock = BLOCK_SUBBLOCKS (block); + subblock; + subblock = BLOCK_CHAIN (subblock)) + mark_blocks_with_used_vars (subblock); +} + +/* Mark the used attribute on blocks correctly. */ + +static void +mark_used_blocks (void) +{ + mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl)); +} + + +struct tree_opt_pass pass_mark_used_blocks = +{ + "blocks", /* name */ + NULL, /* gate */ + mark_used_blocks, /* execute */ + NULL, /* sub */ + NULL, /* next */ + 0, /* static_pass_number */ + 0, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_dump_func, /* todo_flags_finish */ + 0 /* letter */ +};