X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcalls.c;h=4074dbd8badb5c5620455c9c81da3d7cac5cc194;hb=772007c8cfdc258c793a8cc85529568f7234e4fa;hp=3c4cbf8949a69349e9f48cb3c0ceb0e6bdd18601;hpb=0a227ed5edeaf150b5ae49ffabc8f9583f6c301a;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/calls.c b/gcc/calls.c index 3c4cbf8949a..4074dbd8bad 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -17,8 +17,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" @@ -570,17 +570,8 @@ flags_from_decl_or_type (tree exp) if (DECL_P (exp)) { - struct cgraph_rtl_info *i = cgraph_rtl_info (exp); type = TREE_TYPE (exp); - if (i) - { - if (i->pure_function) - flags |= ECF_PURE | ECF_LIBCALL_BLOCK; - if (i->const_function) - flags |= ECF_CONST | ECF_LIBCALL_BLOCK; - } - /* The function exp may have the `malloc' attribute. */ if (DECL_IS_MALLOC (exp)) flags |= ECF_MALLOC; @@ -1453,7 +1444,7 @@ rtx_for_function_call (tree fndecl, tree addr) Mark all register-parms as living through the call, putting these USE insns in the CALL_INSN_FUNCTION_USAGE field. - When IS_SIBCALL, perform the check_sibcall_overlap_argument_overlap + When IS_SIBCALL, perform the check_sibcall_argument_overlap checking, setting *SIBCALL_FAILURE if appropriate. */ static void @@ -1864,6 +1855,7 @@ expand_call (tree exp, rtx target, int ignore) int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; + char *stack_usage_map_buf = NULL; int old_stack_allocated; @@ -1964,17 +1956,7 @@ expand_call (tree exp, rtx target, int ignore) { struct_value_size = int_size_in_bytes (TREE_TYPE (exp)); - if (CALL_EXPR_HAS_RETURN_SLOT_ADDR (exp)) - { - /* The structure value address arg is already in actparms. - Pull it out. It might be nice to just leave it there, but - we need to set structure_value_addr. */ - tree return_arg = TREE_VALUE (actparms); - actparms = TREE_CHAIN (actparms); - structure_value_addr = expand_expr (return_arg, NULL_RTX, - VOIDmode, EXPAND_NORMAL); - } - else if (target && MEM_P (target)) + if (target && MEM_P (target) && CALL_EXPR_RETURN_SLOT_OPT (exp)) structure_value_addr = XEXP (target, 0); else { @@ -2265,6 +2247,9 @@ expand_call (tree exp, rtx target, int ignore) if (pass && (flags & (ECF_LIBCALL_BLOCK | ECF_MALLOC))) start_sequence (); + if (pass == 0 && cfun->stack_protect_guard) + stack_protect_epilogue (); + adjusted_args_size = args_size; /* Compute the actual size of the argument block required. The variable and constant sizes must be combined, the size may have to be rounded, @@ -2360,7 +2345,10 @@ expand_call (tree exp, rtx target, int ignore) highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed); #endif - stack_usage_map = alloca (highest_outgoing_arg_in_use); + if (stack_usage_map_buf) + free (stack_usage_map_buf); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; if (initial_highest_arg_in_use) memcpy (stack_usage_map, initial_stack_usage_map, @@ -2465,7 +2453,10 @@ expand_call (tree exp, rtx target, int ignore) = stack_arg_under_construction; stack_arg_under_construction = 0; /* Make a new map for the new argument list. */ - stack_usage_map = alloca (highest_outgoing_arg_in_use); + if (stack_usage_map_buf) + free (stack_usage_map_buf); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; memset (stack_usage_map, 0, highest_outgoing_arg_in_use); highest_outgoing_arg_in_use = 0; } @@ -2520,9 +2511,10 @@ expand_call (tree exp, rtx target, int ignore) { if (pcc_struct_value) valreg = hard_function_value (build_pointer_type (TREE_TYPE (exp)), - fndecl, (pass == 0)); + fndecl, NULL, (pass == 0)); else - valreg = hard_function_value (TREE_TYPE (exp), fndecl, (pass == 0)); + valreg = hard_function_value (TREE_TYPE (exp), fndecl, fntype, + (pass == 0)); } /* Precompute all register parameters. It isn't safe to compute anything @@ -3019,6 +3011,9 @@ expand_call (tree exp, rtx target, int ignore) emit_move_insn (virtual_stack_dynamic_rtx, stack_pointer_rtx); } + if (stack_usage_map_buf) + free (stack_usage_map_buf); + return target; } @@ -3213,6 +3208,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, /* Size of the stack reserved for parameter registers. */ int initial_highest_arg_in_use = highest_outgoing_arg_in_use; char *initial_stack_usage_map = stack_usage_map; + char *stack_usage_map_buf = NULL; rtx struct_value = targetm.calls.struct_value_rtx (0, 0); @@ -3265,7 +3261,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, { #ifdef PCC_STATIC_STRUCT_RETURN rtx pointer_reg - = hard_function_value (build_pointer_type (tfom), 0, 0); + = hard_function_value (build_pointer_type (tfom), 0, 0, 0); mem_value = gen_rtx_MEM (outmode, pointer_reg); pcc_struct_value = 1; if (value == 0) @@ -3491,7 +3487,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use, needed); #endif - stack_usage_map = alloca (highest_outgoing_arg_in_use); + stack_usage_map_buf = xmalloc (highest_outgoing_arg_in_use); + stack_usage_map = stack_usage_map_buf; if (initial_highest_arg_in_use) memcpy (stack_usage_map, initial_stack_usage_map, @@ -3629,6 +3626,28 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, stack_usage_map[i] = 1; NO_DEFER_POP; + + if (flags & ECF_CONST) + { + rtx use; + + /* Indicate argument access so that alias.c knows that these + values are live. */ + if (argblock) + use = plus_constant (argblock, + argvec[argnum].locate.offset.constant); + else + /* When arguments are pushed, trying to tell alias.c where + exactly this argument is won't work, because the + auto-increment causes confusion. So we merely indicate + that we access something with a known mode somewhere on + the stack. */ + use = gen_rtx_PLUS (Pmode, virtual_outgoing_args_rtx, + gen_rtx_SCRATCH (Pmode)); + use = gen_rtx_MEM (argvec[argnum].mode, use); + use = gen_rtx_USE (VOIDmode, use); + call_fusage = gen_rtx_EXPR_LIST (VOIDmode, use, call_fusage); + } } } @@ -3845,6 +3864,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, stack_usage_map = initial_stack_usage_map; } + if (stack_usage_map_buf) + free (stack_usage_map_buf); + return value; } @@ -4057,6 +4079,43 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, stack_arg_under_construction--; } + /* Check for overlap with already clobbered argument area. */ + if ((flags & ECF_SIBCALL) && MEM_P (arg->value)) + { + int i = -1; + unsigned HOST_WIDE_INT k; + rtx x = arg->value; + + if (XEXP (x, 0) == current_function_internal_arg_pointer) + i = 0; + else if (GET_CODE (XEXP (x, 0)) == PLUS + && XEXP (XEXP (x, 0), 0) == + current_function_internal_arg_pointer + && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT) + i = INTVAL (XEXP (XEXP (x, 0), 1)); + else + i = -1; + + if (i >= 0) + { +#ifdef ARGS_GROW_DOWNWARD + i = -i - arg->locate.size.constant; +#endif + if (arg->locate.size.constant > 0) + { + unsigned HOST_WIDE_INT sc = arg->locate.size.constant; + + for (k = 0; k < sc; k++) + if (i + k < stored_args_map->n_bits + && TEST_BIT (stored_args_map, i + k)) + { + sibcall_failure = 1; + break; + } + } + } + } + /* Don't allow anything left on stack from computation of argument to alloca. */ if (flags & ECF_MAY_BE_ALLOCA)