X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fgimple-low.c;h=f6deba179389d0e3019eb64da162eeb4858783eb;hp=39c735197a7cf30098102ee8f91486fe4dd8e464;hb=451061e0d9ef319a5ee165b2328ae982432e5871;hpb=264ee46dc407e36464dc4b86c3c14961d393623d diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 39c735197a7..f6deba17938 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -1,6 +1,6 @@ /* GIMPLE lowering pass. Converts High GIMPLE into Low GIMPLE. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -24,22 +24,13 @@ along with GCC; see the file COPYING3. If not see #include "coretypes.h" #include "tm.h" #include "tree.h" -#include "rtl.h" -#include "varray.h" #include "gimple.h" #include "tree-iterator.h" #include "tree-inline.h" -#include "diagnostic.h" -#include "langhooks.h" -#include "langhooks-def.h" #include "tree-flow.h" -#include "timevar.h" -#include "except.h" -#include "hashtab.h" #include "flags.h" #include "function.h" -#include "expr.h" -#include "toplev.h" +#include "diagnostic-core.h" #include "tree-pass.h" /* The differences between High GIMPLE and Low GIMPLE are the @@ -76,6 +67,9 @@ struct lower_data of the function. */ VEC(return_statements_t,heap) *return_statements; + /* True if the current statement cannot fall through. */ + bool cannot_fallthru; + /* True if the function calls __builtin_setjmp. */ bool calls_builtin_setjmp; }; @@ -154,11 +148,6 @@ lower_function_body (void) x = gimple_build_label (t.label); gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); - - /* Remove the line number from the representative return statement. - It now fills in for many such returns. Failure to remove this - will result in incorrect results for coverage analysis. */ - gimple_set_location (t.stmt, UNKNOWN_LOCATION); gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } @@ -180,7 +169,7 @@ lower_function_body (void) and insert. */ disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); arg = build_addr (disp_label, current_function_decl); - t = implicit_built_in_decls[BUILT_IN_SETJMP_DISPATCHER]; + t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER); x = gimple_build_call (t, 1, arg); gimple_call_set_lhs (x, disp_var); @@ -199,7 +188,7 @@ lower_function_body (void) return 0; } -struct gimple_opt_pass pass_lower_cf = +struct gimple_opt_pass pass_lower_cf = { { GIMPLE_PASS, @@ -214,30 +203,33 @@ struct gimple_opt_pass pass_lower_cf = PROP_gimple_lcf, /* properties_provided */ 0, /* properties_destroyed */ 0, /* todo_flags_start */ - TODO_dump_func /* todo_flags_finish */ + 0 /* todo_flags_finish */ } }; + /* Verify if the type of the argument matches that of the function declaration. If we cannot verify this or there is a mismatch, return false. */ -bool -gimple_check_call_args (gimple stmt) +static bool +gimple_check_call_args (gimple stmt, tree fndecl) { - tree fndecl, parms, p; + tree parms, p; unsigned int i, nargs; + /* Calls to internal functions always match their signature. */ + if (gimple_call_internal_p (stmt)) + return true; + nargs = gimple_call_num_args (stmt); /* Get argument types for verification. */ - fndecl = gimple_call_fndecl (stmt); - parms = NULL_TREE; if (fndecl) parms = TYPE_ARG_TYPES (TREE_TYPE (fndecl)); - else if (POINTER_TYPE_P (TREE_TYPE (gimple_call_fn (stmt)))) - parms = TYPE_ARG_TYPES (TREE_TYPE (TREE_TYPE (gimple_call_fn (stmt)))); + else + parms = TYPE_ARG_TYPES (gimple_call_fntype (stmt)); /* Verify if the type of the argument matches that of the function declaration. If we cannot verify this or there is a mismatch, @@ -246,7 +238,7 @@ gimple_check_call_args (gimple stmt) { for (i = 0, p = DECL_ARGUMENTS (fndecl); i < nargs; - i++, p = TREE_CHAIN (p)) + i++, p = DECL_CHAIN (p)) { /* We cannot distinguish a varargs function from the case of excess parameters, still deferring the inlining decision @@ -284,6 +276,25 @@ gimple_check_call_args (gimple stmt) return true; } +/* Verify if the type of the argument and lhs of CALL_STMT matches + that of the function declaration CALLEE. + If we cannot verify this or there is a mismatch, return false. */ + +bool +gimple_check_call_matching_types (gimple call_stmt, tree callee) +{ + tree lhs; + + if ((DECL_RESULT (callee) + && !DECL_BY_REFERENCE (DECL_RESULT (callee)) + && (lhs = gimple_call_lhs (call_stmt)) != NULL_TREE + && !useless_type_conversion_p (TREE_TYPE (DECL_RESULT (callee)), + TREE_TYPE (lhs)) + && !fold_convertible_p (TREE_TYPE (DECL_RESULT (callee)), lhs)) + || !gimple_check_call_args (call_stmt, callee)) + return false; + return true; +} /* Lower sequence SEQ. Unlike gimplification the statements are not relowered when they are changed -- if this has to be done, the lowering routine must @@ -306,7 +317,7 @@ static void lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data) { gimple stmt; - + stmt = gsi_stmt (*gsi); lower_sequence (gimple_omp_body (stmt), data); @@ -317,7 +328,12 @@ lower_omp_directive (gimple_stmt_iterator *gsi, struct lower_data *data) } -/* Lower statement GSI. DATA is passed through the recursion. */ +/* Lower statement GSI. DATA is passed through the recursion. We try to + track the fallthruness of statements and get rid of unreachable return + statements in order to prevent the EH lowering pass from adding useless + edges that can cause bogus warnings to be issued later; this guess need + not be 100% accurate, simply be conservative and reset cannot_fallthru + to false if we don't know. */ static void lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) @@ -330,36 +346,66 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) { case GIMPLE_BIND: lower_gimple_bind (gsi, data); + /* Propagate fallthruness. */ return; case GIMPLE_COND: - /* The gimplifier has already lowered this into gotos. */ - break; + case GIMPLE_GOTO: + case GIMPLE_SWITCH: + data->cannot_fallthru = true; + gsi_next (gsi); + return; case GIMPLE_RETURN: - lower_gimple_return (gsi, data); + if (data->cannot_fallthru) + { + gsi_remove (gsi, false); + /* Propagate fallthruness. */ + } + else + { + lower_gimple_return (gsi, data); + data->cannot_fallthru = true; + } return; case GIMPLE_TRY: - lower_sequence (gimple_try_eval (stmt), data); - lower_sequence (gimple_try_cleanup (stmt), data); + { + bool try_cannot_fallthru; + lower_sequence (gimple_try_eval (stmt), data); + try_cannot_fallthru = data->cannot_fallthru; + data->cannot_fallthru = false; + lower_sequence (gimple_try_cleanup (stmt), data); + /* See gimple_stmt_may_fallthru for the rationale. */ + if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY) + { + data->cannot_fallthru |= try_cannot_fallthru; + gsi_next (gsi); + return; + } + } break; case GIMPLE_CATCH: + data->cannot_fallthru = false; lower_sequence (gimple_catch_handler (stmt), data); break; case GIMPLE_EH_FILTER: + data->cannot_fallthru = false; lower_sequence (gimple_eh_filter_failure (stmt), data); break; + case GIMPLE_EH_ELSE: + lower_sequence (gimple_eh_else_n_body (stmt), data); + lower_sequence (gimple_eh_else_e_body (stmt), data); + break; + case GIMPLE_NOP: case GIMPLE_ASM: case GIMPLE_ASSIGN: - case GIMPLE_GOTO: case GIMPLE_PREDICT: case GIMPLE_LABEL: - case GIMPLE_SWITCH: case GIMPLE_EH_MUST_NOT_THROW: case GIMPLE_OMP_FOR: case GIMPLE_OMP_SECTIONS: @@ -383,21 +429,16 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) && DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL && DECL_FUNCTION_CODE (decl) == BUILT_IN_SETJMP) { - data->calls_builtin_setjmp = true; lower_builtin_setjmp (gsi); + data->cannot_fallthru = false; + data->calls_builtin_setjmp = true; return; } - /* After a noreturn call, remove a subsequent GOTO or RETURN that might - have been mechanically added; this will prevent the EH lowering pass - from adding useless edges and thus complicating the initial CFG. */ if (decl && (flags_from_decl_or_type (decl) & ECF_NORETURN)) { + data->cannot_fallthru = true; gsi_next (gsi); - if (!gsi_end_p (*gsi) - && (gimple_code (gsi_stmt (*gsi)) == GIMPLE_GOTO - || gimple_code (gsi_stmt (*gsi)) == GIMPLE_RETURN)) - gsi_remove (gsi, false); return; } } @@ -405,13 +446,20 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) case GIMPLE_OMP_PARALLEL: case GIMPLE_OMP_TASK: + data->cannot_fallthru = false; lower_omp_directive (gsi, data); + data->cannot_fallthru = false; return; + case GIMPLE_TRANSACTION: + lower_sequence (gimple_transaction_body (stmt), data); + break; + default: gcc_unreachable (); } + data->cannot_fallthru = false; gsi_next (gsi); } @@ -585,7 +633,7 @@ block_may_fallthru (const_tree block) { case GOTO_EXPR: case RETURN_EXPR: - /* Easy cases. If the last statement of the block implies + /* Easy cases. If the last statement of the block implies control transfer, then we can't fall through. */ return false; @@ -628,7 +676,7 @@ block_may_fallthru (const_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)); @@ -655,14 +703,14 @@ gimple_stmt_may_fallthru (gimple stmt) case GIMPLE_GOTO: case GIMPLE_RETURN: case GIMPLE_RESX: - /* Easy cases. If the last statement of the seq implies + /* Easy cases. If the last statement of the seq implies control transfer, then we can't fall through. */ return false; case GIMPLE_SWITCH: - /* Switch has already been lowered and represents a - branch to a selected label and hence can not fall through. */ - return true; + /* Switch has already been lowered and represents a branch + to a selected label and hence can't fall through. */ + return false; case GIMPLE_COND: /* GIMPLE_COND's are already lowered into a two-way branch. They @@ -688,13 +736,14 @@ gimple_stmt_may_fallthru (gimple stmt) return (gimple_seq_may_fallthru (gimple_try_eval (stmt)) && gimple_seq_may_fallthru (gimple_try_cleanup (stmt))); - case GIMPLE_ASSIGN: - return true; + case GIMPLE_EH_ELSE: + return (gimple_seq_may_fallthru (gimple_eh_else_n_body (stmt)) + || gimple_seq_may_fallthru (gimple_eh_else_e_body (stmt))); case GIMPLE_CALL: /* Functions that do not return do not fall through. */ return (gimple_call_flags (stmt) & ECF_NORETURN) == 0; - + default: return true; } @@ -727,7 +776,14 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) tmp_rs = *VEC_index (return_statements_t, data->return_statements, i); if (gimple_return_retval (stmt) == gimple_return_retval (tmp_rs.stmt)) - goto found; + { + /* Remove the line number from the representative return statement. + It now fills in for many such returns. Failure to remove this + will result in incorrect results for coverage analysis. */ + gimple_set_location (tmp_rs.stmt, UNKNOWN_LOCATION); + + goto found; + } } /* Not found. Create a new label and record the return statement. */ @@ -737,6 +793,9 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) /* Generate a goto statement and remove the return statement. */ found: + /* When not optimizing, make sure user returns are preserved. */ + if (!optimize && gimple_has_location (stmt)) + DECL_ARTIFICIAL (tmp_rs.label) = 0; t = gimple_build_goto (tmp_rs.label); gimple_set_location (t, gimple_location (stmt)); gimple_set_block (t, gimple_block (stmt)); @@ -744,7 +803,7 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) gsi_remove (gsi, false); } -/* Lower a __builtin_setjmp TSI. +/* Lower a __builtin_setjmp GSI. __builtin_setjmp is passed a pointer to an array of five words (not all will be used on all machines). It operates similarly to the C @@ -815,7 +874,7 @@ lower_builtin_setjmp (gimple_stmt_iterator *gsi) /* Build '__builtin_setjmp_setup (BUF, NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); - t = implicit_built_in_decls[BUILT_IN_SETJMP_SETUP]; + t = builtin_decl_implicit (BUILT_IN_SETJMP_SETUP); g = gimple_build_call (t, 2, gimple_call_arg (stmt, 0), arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); @@ -824,8 +883,7 @@ lower_builtin_setjmp (gimple_stmt_iterator *gsi) /* Build 'DEST = 0' and insert. */ if (dest) { - g = gimple_build_assign (dest, fold_convert_loc (loc, TREE_TYPE (dest), - integer_zero_node)); + g = gimple_build_assign (dest, build_zero_cst (TREE_TYPE (dest))); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); gsi_insert_before (gsi, g, GSI_SAME_STMT); @@ -841,7 +899,7 @@ lower_builtin_setjmp (gimple_stmt_iterator *gsi) /* Build '__builtin_setjmp_receiver (NEXT_LABEL)' and insert. */ arg = build_addr (next_label, current_function_decl); - t = implicit_built_in_decls[BUILT_IN_SETJMP_RECEIVER]; + t = builtin_decl_implicit (BUILT_IN_SETJMP_RECEIVER); g = gimple_build_call (t, 1, arg); gimple_set_location (g, loc); gimple_set_block (g, gimple_block (stmt)); @@ -874,7 +932,7 @@ record_vars_into (tree vars, tree fn) if (fn != current_function_decl) push_cfun (DECL_STRUCT_FUNCTION (fn)); - for (; vars; vars = TREE_CHAIN (vars)) + for (; vars; vars = DECL_CHAIN (vars)) { tree var = vars; @@ -888,8 +946,9 @@ record_vars_into (tree vars, tree fn) continue; /* Record the variable. */ - cfun->local_decls = tree_cons (NULL_TREE, var, - cfun->local_decls); + add_local_decl (cfun, var); + if (gimple_referenced_vars (cfun)) + add_referenced_var (var); } if (fn != current_function_decl)