diff options
author | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
---|---|---|
committer | kan <kan@FreeBSD.org> | 2003-07-11 03:40:53 +0000 |
commit | b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180 (patch) | |
tree | f6b0610f4a17fd26aa234354f050080f789861a4 /contrib/gcc/calls.c | |
parent | 52e69d78eee5612ac195e0701a5cebe40d1ab0e1 (diff) | |
download | FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.zip FreeBSD-src-b2a8872fbe1ec1c49094559ac7b78e6ea4ab7180.tar.gz |
Gcc 3.3.1-pre as of 2003-07-11.
Diffstat (limited to 'contrib/gcc/calls.c')
-rw-r--r-- | contrib/gcc/calls.c | 292 |
1 files changed, 160 insertions, 132 deletions
diff --git a/contrib/gcc/calls.c b/contrib/gcc/calls.c index 9a059a0..b5a5123 100644 --- a/contrib/gcc/calls.c +++ b/contrib/gcc/calls.c @@ -1,6 +1,6 @@ /* Convert function calls to rtl insns, for GNU C compiler. Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998 - 1999, 2000, 2001 Free Software Foundation, Inc. + 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. This file is part of GCC. @@ -33,6 +33,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "tm_p.h" #include "timevar.h" #include "sbitmap.h" +#include "langhooks.h" +#include "target.h" +#include "except.h" #if !defined FUNCTION_OK_FOR_SIBCALL #define FUNCTION_OK_FOR_SIBCALL(DECL) 1 @@ -91,7 +94,7 @@ struct arg_data /* Number of registers to use. 0 means put the whole arg in registers. Also 0 if not passed in registers. */ int partial; - /* Non-zero if argument must be passed on stack. + /* Nonzero if argument must be passed on stack. Note that some arguments may be passed on the stack even though pass_on_stack is zero, just because FUNCTION_ARG says so. pass_on_stack identifies arguments that *cannot* go in registers. */ @@ -126,7 +129,7 @@ struct arg_data struct args_size alignment_pad; }; -/* A vector of one char per byte of stack space. A byte if non-zero if +/* A vector of one char per byte of stack space. A byte if nonzero if the corresponding stack location has been used. This vector is used to prevent a function call within an argument from clobbering any stack already set up. */ @@ -225,6 +228,7 @@ static int check_sibcall_argument_overlap PARAMS ((rtx, struct arg_data *)); static int combine_pending_stack_adjustment_and_call PARAMS ((int, struct args_size *, int)); +static tree fix_unsafe_tree PARAMS ((tree)); #ifdef REG_PARM_STACK_SPACE static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *)); @@ -614,6 +618,8 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size, if (ecf_flags & ECF_NOTHROW) REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_EH_REGION, const0_rtx, REG_NOTES (call_insn)); + else + note_eh_region_may_contain_throw (); if (ecf_flags & ECF_NORETURN) REG_NOTES (call_insn) = gen_rtx_EXPR_LIST (REG_NORETURN, const0_rtx, @@ -799,6 +805,21 @@ setjmp_call_p (fndecl) return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE; } +/* Return true when exp contains alloca call. */ +bool +alloca_call_p (exp) + tree exp; +{ + if (TREE_CODE (exp) == CALL_EXPR + && TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR + && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (exp, 0), 0)) + == FUNCTION_DECL) + && (special_function_p (TREE_OPERAND (TREE_OPERAND (exp, 0), 0), + 0) & ECF_MAY_BE_ALLOCA)) + return true; + return false; +} + /* Detect flags (function attributes) from the function decl or type node. */ static int @@ -876,6 +897,12 @@ precompute_register_parameters (num_actuals, args, reg_parm_seen) emit_queue (); } + /* If the value is a non-legitimate constant, force it into a + pseudo now. TLS symbols sometimes need a call to resolve. */ + if (CONSTANT_P (args[i].value) + && !LEGITIMATE_CONSTANT_P (args[i].value)) + args[i].value = force_reg (args[i].mode, args[i].value); + /* If we are to promote the function arg to a wider mode, do it now. */ @@ -967,11 +994,8 @@ save_fixed_argument_area (reg_parm_stack_space, argblock, if (save_mode == BLKmode) { save_area = assign_stack_temp (BLKmode, num_to_save, 0); - /* Cannot use emit_block_move here because it can be done by a - library call which in turn gets into this place again and deadly - infinite recursion happens. */ - move_by_pieces (validize_mem (save_area), stack_area, num_to_save, - PARM_BOUNDARY); + emit_block_move (validize_mem (save_area), stack_area, + GEN_INT (num_to_save), BLOCK_OP_CALL_PARM); } else { @@ -1008,11 +1032,9 @@ restore_fixed_argument_area (save_area, argblock, high_to_save, low_to_save) if (save_mode != BLKmode) emit_move_insn (stack_area, save_area); else - /* Cannot use emit_block_move here because it can be done by a library - call which in turn gets into this place again and deadly infinite - recursion happens. */ - move_by_pieces (stack_area, validize_mem (save_area), - high_to_save - low_to_save + 1, PARM_BOUNDARY); + emit_block_move (stack_area, validize_mem (save_area), + GEN_INT (high_to_save - low_to_save + 1), + BLOCK_OP_CALL_PARM); } #endif /* REG_PARM_STACK_SPACE */ @@ -1053,7 +1075,6 @@ store_unaligned_arguments_into_pseudos (args, num_actuals) this means we must skip the empty high order bytes when calculating the bit offset. */ if (BYTES_BIG_ENDIAN - && !FUNCTION_ARG_REG_LITTLE_ENDIAN && bytes < UNITS_PER_WORD) big_endian_correction = (BITS_PER_WORD - (bytes * BITS_PER_UNIT)); @@ -1539,8 +1560,8 @@ precompute_arguments (flags, num_actuals, args) args[i].initial_value = gen_lowpart_SUBREG (mode, args[i].value); SUBREG_PROMOTED_VAR_P (args[i].initial_value) = 1; - SUBREG_PROMOTED_UNSIGNED_P (args[i].initial_value) - = args[i].unsignedp; + SUBREG_PROMOTED_UNSIGNED_SET (args[i].initial_value, + args[i].unsignedp); } #endif } @@ -1645,6 +1666,7 @@ compute_argument_addresses (args, argblock, num_actuals) addr = plus_constant (addr, arg_offset); args[i].stack = gen_rtx_MEM (args[i].mode, addr); + set_mem_align (args[i].stack, PARM_BOUNDARY); set_mem_attributes (args[i].stack, TREE_TYPE (args[i].tree_value), 1); @@ -1655,6 +1677,7 @@ compute_argument_addresses (args, argblock, num_actuals) addr = plus_constant (addr, arg_offset); args[i].stack_slot = gen_rtx_MEM (args[i].mode, addr); + set_mem_align (args[i].stack_slot, PARM_BOUNDARY); set_mem_attributes (args[i].stack_slot, TREE_TYPE (args[i].tree_value), 1); @@ -1674,12 +1697,12 @@ compute_argument_addresses (args, argblock, num_actuals) FNDECL is the tree node for the target function. For an indirect call FNDECL will be NULL_TREE. - EXP is the CALL_EXPR for this call. */ + ADDR is the operand 0 of CALL_EXPR for this call. */ static rtx -rtx_for_function_call (fndecl, exp) +rtx_for_function_call (fndecl, addr) tree fndecl; - tree exp; + tree addr; { rtx funexp; @@ -1703,7 +1726,7 @@ rtx_for_function_call (fndecl, exp) rtx funaddr; push_temp_slots (); funaddr = funexp - = expand_expr (TREE_OPERAND (exp, 0), NULL_RTX, VOIDmode, 0); + = expand_expr (addr, NULL_RTX, VOIDmode, 0); pop_temp_slots (); /* FUNEXP can't be BLKmode. */ emit_queue (); } @@ -1881,7 +1904,7 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr) NULL_RTX, BITS_PER_UNIT); seq = get_insns (); end_sequence (); - emit_insns_before (seq, first_insn); + emit_insn_before (seq, first_insn); emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX); } } @@ -1904,7 +1927,7 @@ try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr) warning_with_decl (fndecl, "inlining failed in call to `%s'"); warning ("called from here"); } - mark_addressable (fndecl); + (*lang_hooks.mark_addressable) (fndecl); return (rtx) (size_t) - 1; } @@ -1970,7 +1993,7 @@ combine_pending_stack_adjustment_and_call (unadjusted_args_size, /* Scan X expression if it does not dereference any argument slots we already clobbered by tail call arguments (as noted in stored_args_map bitmap). - Return non-zero if X expression dereferences such argument slots, + Return nonzero if X expression dereferences such argument slots, zero otherwise. */ static int @@ -2033,7 +2056,7 @@ check_sibcall_argument_overlap_1 (x) /* Scan sequence after INSN if it does not dereference any argument slots we already clobbered by tail call arguments (as noted in stored_args_map bitmap). Add stack slots for ARG to stored_args_map bitmap afterwards. - Return non-zero if sequence after INSN dereferences such argument slots, + Return nonzero if sequence after INSN dereferences such argument slots, zero otherwise. */ static int @@ -2204,6 +2227,7 @@ expand_call (exp, target, ignore) int old_stack_allocated; rtx call_fusage; tree p = TREE_OPERAND (exp, 0); + tree addr = TREE_OPERAND (exp, 0); int i; /* The alignment of the stack, in bits. */ HOST_WIDE_INT preferred_stack_boundary; @@ -2239,7 +2263,7 @@ expand_call (exp, target, ignore) warning_with_decl (fndecl, "can't inline call to `%s'"); warning ("called from here"); } - mark_addressable (fndecl); + (*lang_hooks.mark_addressable) (fndecl); } flags |= flags_from_decl_or_type (fndecl); @@ -2285,7 +2309,7 @@ expand_call (exp, target, ignore) /* In case this is a static function, note that it has been used. */ if (! TREE_ADDRESSABLE (fndecl)) - mark_addressable (fndecl); + (*lang_hooks.mark_addressable) (fndecl); is_integrable = 0; } } @@ -2325,7 +2349,7 @@ expand_call (exp, target, ignore) preferred_stack_boundary = PREFERRED_STACK_BOUNDARY; /* Operand 0 is a pointer-to-function; get the type of the function. */ - funtype = TREE_TYPE (TREE_OPERAND (exp, 0)); + funtype = TREE_TYPE (addr); if (! POINTER_TYPE_P (funtype)) abort (); funtype = TREE_TYPE (funtype); @@ -2462,8 +2486,8 @@ expand_call (exp, target, ignore) /* Tail recursion fails, when we are not dealing with recursive calls. */ if (!try_tail_recursion - || TREE_CODE (TREE_OPERAND (exp, 0)) != ADDR_EXPR - || TREE_OPERAND (TREE_OPERAND (exp, 0), 0) != current_function_decl) + || TREE_CODE (addr) != ADDR_EXPR + || TREE_OPERAND (addr, 0) != current_function_decl) try_tail_recursion = 0; /* Rest of purposes for tail call optimizations to fail. */ @@ -2487,19 +2511,19 @@ expand_call (exp, target, ignore) reload insns generated to fix things up would appear before the sibcall_epilogue. */ || fndecl == NULL_TREE - || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP)) - || TREE_THIS_VOLATILE (fndecl) + || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP | ECF_NORETURN)) || !FUNCTION_OK_FOR_SIBCALL (fndecl) /* If this function requires more stack slots than the current function, we cannot change it into a sibling call. */ || args_size.constant > current_function_args_size /* If the callee pops its own arguments, then it must pop exactly the same number of arguments as the current function. */ - || RETURN_POPS_ARGS (fndecl, funtype, args_size.constant) - != RETURN_POPS_ARGS (current_function_decl, - TREE_TYPE (current_function_decl), - current_function_args_size)) - try_tail_call = 0; + || (RETURN_POPS_ARGS (fndecl, funtype, args_size.constant) + != RETURN_POPS_ARGS (current_function_decl, + TREE_TYPE (current_function_decl), + current_function_args_size)) + || !(*lang_hooks.decls.ok_for_sibcall) (fndecl)) + try_tail_call = 0; if (try_tail_call || try_tail_recursion) { @@ -2544,7 +2568,7 @@ expand_call (exp, target, ignore) } /* Do the same for the function address if it is an expression. */ if (!fndecl) - TREE_OPERAND (exp, 0) = fix_unsafe_tree (TREE_OPERAND (exp, 0)); + addr = fix_unsafe_tree (addr); /* Expanding one of those dangerous arguments could have added cleanups, but otherwise give it a whirl. */ if (any_pending_cleanups (1)) @@ -2938,7 +2962,7 @@ expand_call (exp, target, ignore) be deferred during the evaluation of the arguments. */ NO_DEFER_POP; - funexp = rtx_for_function_call (fndecl, exp); + funexp = rtx_for_function_call (fndecl, addr); /* Figure out the register where the value, if any, will come back. */ valreg = 0; @@ -3089,7 +3113,7 @@ expand_call (exp, target, ignore) { insns = get_insns (); end_sequence (); - emit_insns (insns); + emit_insn (insns); } else { @@ -3143,7 +3167,7 @@ expand_call (exp, target, ignore) /* Write out the sequence. */ insns = get_insns (); end_sequence (); - emit_insns (insns); + emit_insn (insns); valreg = temp; } @@ -3288,7 +3312,7 @@ expand_call (exp, target, ignore) } target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset); SUBREG_PROMOTED_VAR_P (target) = 1; - SUBREG_PROMOTED_UNSIGNED_P (target) = unsignedp; + SUBREG_PROMOTED_UNSIGNED_SET (target, unsignedp); } #endif @@ -3327,9 +3351,9 @@ expand_call (exp, target, ignore) if (save_mode != BLKmode) emit_move_insn (stack_area, args[i].save_area); else - emit_block_move (stack_area, - validize_mem (args[i].save_area), - GEN_INT (args[i].size.constant)); + emit_block_move (stack_area, args[i].save_area, + GEN_INT (args[i].size.constant), + BLOCK_OP_CALL_PARM); } highest_outgoing_arg_in_use = initial_highest_arg_in_use; @@ -3430,7 +3454,7 @@ expand_call (exp, target, ignore) tail_recursion_label)); } else - emit_insns (normal_call_insns); + emit_insn (normal_call_insns); currently_expanding_call--; @@ -3494,6 +3518,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) int reg_parm_stack_space = 0; int needed; rtx before_call; + tree tfom; /* type_for_mode (outmode, 0) */ #ifdef REG_PARM_STACK_SPACE /* Define the boundary of the register parm stack space that needs to be @@ -3555,27 +3580,31 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) /* If this kind of value comes back in memory, decide where in memory it should come back. */ - if (outmode != VOIDmode && aggregate_value_p (type_for_mode (outmode, 0))) + if (outmode != VOIDmode) { + tfom = (*lang_hooks.types.type_for_mode) (outmode, 0); + if (aggregate_value_p (tfom)) + { #ifdef PCC_STATIC_STRUCT_RETURN - rtx pointer_reg - = hard_function_value (build_pointer_type (type_for_mode (outmode, 0)), - 0, 0); - mem_value = gen_rtx_MEM (outmode, pointer_reg); - pcc_struct_value = 1; - if (value == 0) - value = gen_reg_rtx (outmode); + rtx pointer_reg + = hard_function_value (build_pointer_type (tfom), 0, 0); + mem_value = gen_rtx_MEM (outmode, pointer_reg); + pcc_struct_value = 1; + if (value == 0) + value = gen_reg_rtx (outmode); #else /* not PCC_STATIC_STRUCT_RETURN */ - struct_value_size = GET_MODE_SIZE (outmode); - if (value != 0 && GET_CODE (value) == MEM) - mem_value = value; - else - mem_value = assign_temp (type_for_mode (outmode, 0), 0, 1, 1); + struct_value_size = GET_MODE_SIZE (outmode); + if (value != 0 && GET_CODE (value) == MEM) + mem_value = value; + else + mem_value = assign_temp (tfom, 0, 1, 1); #endif - - /* This call returns a big structure. */ - flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); + /* This call returns a big structure. */ + flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); + } } + else + tfom = void_type_node; /* ??? Unfinished: must pass the memory address as an argument. */ @@ -3684,6 +3713,16 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) #endif ; + /* loop.c won't look at CALL_INSN_FUNCTION_USAGE of const/pure + functions, so we have to pretend this isn't such a function. */ + if (flags & ECF_LIBCALL_BLOCK) + { + rtx insns = get_insns (); + end_sequence (); + emit_insn (insns); + } + flags &= ~(ECF_CONST | ECF_PURE | ECF_LIBCALL_BLOCK); + /* If this was a CONST function, it is now PURE since it now reads memory. */ if (flags & ECF_CONST) @@ -3696,12 +3735,13 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) slot = val; else if (must_copy) { - slot = assign_temp (type_for_mode (mode, 0), 0, 1, 1); + slot = assign_temp ((*lang_hooks.types.type_for_mode) (mode, 0), + 0, 1, 1); emit_move_insn (slot, val); } else { - tree type = type_for_mode (mode, 0); + tree type = (*lang_hooks.types.type_for_mode) (mode, 0); slot = gen_rtx_MEM (mode, expand_expr (build1 (ADDR_EXPR, @@ -3911,8 +3951,8 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) { save_area = assign_stack_temp (BLKmode, num_to_save, 0); set_mem_align (save_area, PARM_BOUNDARY); - emit_block_move (validize_mem (save_area), stack_area, - GEN_INT (num_to_save)); + emit_block_move (save_area, stack_area, GEN_INT (num_to_save), + BLOCK_OP_CALL_PARM); } else { @@ -3980,8 +4020,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) } } - emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0, - argblock, GEN_INT (argvec[argnum].offset.constant), + emit_push_insn (val, mode, NULL_TREE, NULL_RTX, PARM_BOUNDARY, + partial, reg, 0, argblock, + GEN_INT (argvec[argnum].offset.constant), reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad)); /* Now mark the segment we just used. */ @@ -4068,8 +4109,7 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), - build_function_type (outmode == VOIDmode ? void_type_node - : type_for_mode (outmode, 0), NULL_TREE), + build_function_type (tfom, NULL_TREE), original_args_size.constant, args_size.constant, struct_value_size, FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1), @@ -4109,18 +4149,27 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) { rtx insns; - if (valreg == 0 || GET_CODE (valreg) == PARALLEL) + if (valreg == 0) { insns = get_insns (); end_sequence (); - emit_insns (insns); + emit_insn (insns); } else { rtx note = 0; - rtx temp = gen_reg_rtx (GET_MODE (valreg)); + rtx temp; int i; + if (GET_CODE (valreg) == PARALLEL) + { + temp = gen_reg_rtx (outmode); + emit_group_store (temp, valreg, outmode); + valreg = temp; + } + + temp = gen_reg_rtx (GET_MODE (valreg)); + /* Construct an "equal form" for the value which mentions all the arguments in order as well as the function name. */ for (i = 0; i < nargs; i++) @@ -4154,10 +4203,16 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (value != mem_value) emit_move_insn (value, mem_value); } + else if (GET_CODE (valreg) == PARALLEL) + { + if (value == 0) + value = gen_reg_rtx (outmode); + emit_group_store (value, valreg, outmode); + } else if (value != 0) - emit_move_insn (value, hard_libcall_value (outmode)); + emit_move_insn (value, valreg); else - value = hard_libcall_value (outmode); + value = valreg; } if (ACCUMULATE_OUTGOING_ARGS) @@ -4183,8 +4238,9 @@ emit_library_call_value_1 (retval, orgfun, value, fn_type, outmode, nargs, p) if (save_mode != BLKmode) emit_move_insn (stack_area, save_area); else - emit_block_move (stack_area, validize_mem (save_area), - GEN_INT (high_to_save - low_to_save + 1)); + emit_block_move (stack_area, save_area, + GEN_INT (high_to_save - low_to_save + 1), + BLOCK_OP_CALL_PARM); } #endif @@ -4286,7 +4342,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, FNDECL is the declaration of the function we are calling. - Return non-zero if this arg should cause sibcall failure, + Return nonzero if this arg should cause sibcall failure, zero otherwise. */ static int @@ -4294,7 +4350,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) struct arg_data *arg; rtx argblock; int flags; - int variable_size; + int variable_size ATTRIBUTE_UNUSED; int reg_parm_stack_space; { tree pval = arg->tree_value; @@ -4361,7 +4417,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) arg->save_area = assign_temp (nt, 0, 1, 1); preserve_temp_slots (arg->save_area); emit_block_move (validize_mem (arg->save_area), stack_area, - expr_size (arg->tree_value)); + expr_size (arg->tree_value), + BLOCK_OP_CALL_PARM); } else { @@ -4369,21 +4426,6 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) emit_move_insn (arg->save_area, stack_area); } } - - /* Now that we have saved any slots that will be overwritten - by this store, mark all slots this store will use. We - must do this before we actually expand the argument since - the expansion itself may trigger library calls which might - need to use the same stack slot. We only do it if we can't - pass all arguments to a library call in registers. */ - if (arg->partial) - { - for (i = lower_bound; i < upper_bound; i++) - stack_usage_map[i] = 1; - - /* Set it so that we don't do it again. */ - variable_size = 1; - } } } @@ -4437,7 +4479,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) (partial || TYPE_MODE (TREE_TYPE (pval)) != arg->mode) ? NULL_RTX : arg->stack, - VOIDmode, 0); + VOIDmode, EXPAND_STACK_PARM); /* If we are promoting object (or for any other reason) the mode doesn't agree, convert the mode. */ @@ -4490,8 +4532,8 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) /* This isn't already where we want it on the stack, so put it there. This can either be done with push or copy insns. */ - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, 0, - partial, reg, used - size, argblock, + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, + PARM_BOUNDARY, partial, reg, used - size, argblock, ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space, ARGS_SIZE_RTX (arg->alignment_pad)); @@ -4504,6 +4546,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) { /* BLKmode, at least partly to be pushed. */ + unsigned int parm_align; int excess; rtx size_rtx; @@ -4529,6 +4572,23 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) NULL_RTX, TYPE_MODE (sizetype), 0); } + /* Some types will require stricter alignment, which will be + provided for elsewhere in argument layout. */ + parm_align = MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))); + + /* When an argument is padded down, the block is aligned to + PARM_BOUNDARY, but the actual argument isn't. */ + if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward) + { + if (arg->size.var) + parm_align = BITS_PER_UNIT; + else if (excess) + { + unsigned int excess_align = (excess & -excess) * BITS_PER_UNIT; + parm_align = MIN (parm_align, excess_align); + } + } + if ((flags & ECF_SIBCALL) && GET_CODE (arg->value) == MEM) { /* emit_push_insn might not work properly if arg->value and @@ -4562,42 +4622,9 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) } } - /* Special handling is required if part of the parameter lies in the - register parameter area. The argument may be copied into the stack - slot using memcpy(), but the original contents of the register - parameter area will be restored after the memcpy() call. - - To ensure that the part that lies in the register parameter area - is copied correctly, we emit a separate push for that part. This - push should be small enough to avoid a call to memcpy(). */ -#ifndef STACK_PARMS_IN_REG_PARM_AREA - if (arg->reg && arg->pass_on_stack) -#else - if (1) -#endif - { - if (arg->offset.constant < reg_parm_stack_space && arg->offset.var) - error ("variable offset is passed partially in stack and in reg"); - else if (arg->offset.constant < reg_parm_stack_space && arg->size.var) - error ("variable size is passed partially in stack and in reg"); - else if (arg->offset.constant < reg_parm_stack_space - && ((arg->offset.constant + arg->size.constant) - > reg_parm_stack_space)) - { - rtx size_rtx1 = GEN_INT (reg_parm_stack_space - arg->offset.constant); - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx1, - TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, - excess, argblock, ARGS_SIZE_RTX (arg->offset), - reg_parm_stack_space, - ARGS_SIZE_RTX (arg->alignment_pad)); - } - } - - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, - TYPE_ALIGN (TREE_TYPE (pval)), partial, reg, excess, - argblock, ARGS_SIZE_RTX (arg->offset), - reg_parm_stack_space, + parm_align, partial, reg, excess, argblock, + ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space, ARGS_SIZE_RTX (arg->alignment_pad)); /* Unless this is a partially-in-register argument, the argument is now @@ -4612,6 +4639,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space) arg->value = arg->stack_slot; } + /* Mark all slots this store used. */ if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL) && argblock && ! variable_size && arg->stack) for (i = lower_bound; i < upper_bound; i++) |