X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fgimple-low.c;h=5c7c27f7e13f62e34ccdf66a814151952b8143f5;hb=347465629f7e2933e5a091261fdcffbecf9718f9;hp=ee57d9beda0e8c82f012a6ef4f3d4e909d9a47d0;hpb=9e45f419716a86e6892c802abdc45ea2a2aa65a9;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index ee57d9beda0..5c7c27f7e13 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" @@ -145,7 +144,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 +262,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 +325,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 +344,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) @@ -304,6 +368,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; @@ -452,11 +519,13 @@ record_vars (tree 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, @@ -541,7 +610,7 @@ struct tree_opt_pass pass_remove_useless_vars = 0 /* letter */ }; -/* Mark BLOCK used if it has a used variable in it, then recurse over it's +/* Mark BLOCK used if it has a used variable in it, then recurse over its subblocks. */ static void @@ -569,42 +638,12 @@ mark_blocks_with_used_vars (tree block) mark_blocks_with_used_vars (subblock); } -/* Mark BLOCK used if any of it's subblocks have the USED bit set, or it's - abstract origin is used. */ - -static bool -mark_blocks_with_used_subblocks (tree block) -{ - tree subblock; - - /* The block may have no variables, but still be used, if it's abstract - origin is used. This occurs when we inline functions with no parameters - that call functions with no parameters or local vars (such as - dwarf2/dwarf-die7.c). You end up with a block that has an abstract - origin, no variables, and nothing in the subblocks is used. However, the - block is really used, because it's abstract origin was used. */ - - if (BLOCK_ABSTRACT_ORIGIN (block)) - { - if (TREE_USED (BLOCK_ABSTRACT_ORIGIN (block))) - TREE_USED (block) = true; - } - - for (subblock = BLOCK_SUBBLOCKS (block); - subblock; - subblock = BLOCK_CHAIN (subblock)) - TREE_USED (block) |= mark_blocks_with_used_subblocks (subblock); - return TREE_USED (block); -} - /* Mark the used attribute on blocks correctly. */ static void mark_used_blocks (void) -{ - +{ mark_blocks_with_used_vars (DECL_INITIAL (current_function_decl)); - mark_blocks_with_used_subblocks (DECL_INITIAL (current_function_decl)); }