calls.c (store_one_arg): Set default alignment for BLKmode arguments to BITS_PER_UNIT when...

* calls.c (store_one_arg): Set default alignment for BLKmode arguments
	to BITS_PER_UNIT when ARGS_GROW_DOWNWARD and the padding direction is
	downward.
	* function.c (pad_below):  Always compile.
	(locate_and_pad_parm): If defined ARGS_GROW_DOWNWARD, pad argument to
	alignment when it is not in a register or REG_PARM_STACK_SPACE is true.
	Pad below when the argument is not in a register and the padding
	direction is downward.
	* pa-64.h (MUST_PASS_IN_STACK): Move define to pa.h.
	(PAD_VARARGS_DOWN): Define.
	* pa.c (function_arg_padding): Revise padding directions to make them
	compatible with the 32 and 64-bit runtime architecture documentation.
	(hppa_va_arg):  Add code to handle variable and size zero arguments
	passed by reference on TARGET_64BIT.  Reformat.
	(function_arg): Use a PARALLEL for BLKmode and aggregates args on
	TARGET_64BIT.  Use a DImode PARALLEL for BLKmode args 5 to 8 bytes
	wide when !TARGET_64BIT.  Move forward check for mode==VOIDmode.
	Add comments.
	* pa.h (MAX_PARM_BOUNDARY): Correct define for TARGET_64BIT.
	(RETURN_IN_MEMORY): Return size zero types in memory.
	(FUNCTION_VALUE): Return TFmode in general registers.
	(MUST_PASS_IN_STACK): Define.
	(FUNCTION_ARG_BOUNDARY): Simplify.
	(FUNCTION_ARG_PASS_BY_REFERENCE): Pass variable and zero sized types
	by reference.
	(FUNCTION_ARG_CALLEE_COPIES): Define to FUNCTION_ARG_PASS_BY_REFERENCE.

From-SVN: r57226
This commit is contained in:
John David Anglin 2002-09-17 03:30:37 +00:00 committed by John David Anglin
parent 94313f351a
commit 9dff28ab53
6 changed files with 264 additions and 117 deletions

View File

@ -1,3 +1,33 @@
2002-09-16 John David Anglin <dave@hiauly1.hia.nrc.ca>
* calls.c (store_one_arg): Set default alignment for BLKmode arguments
to BITS_PER_UNIT when ARGS_GROW_DOWNWARD and the padding direction is
downward.
* function.c (pad_below): Always compile.
(locate_and_pad_parm): If defined ARGS_GROW_DOWNWARD, pad argument to
alignment when it is not in a register or REG_PARM_STACK_SPACE is true.
Pad below when the argument is not in a register and the padding
direction is downward.
* pa-64.h (MUST_PASS_IN_STACK): Move define to pa.h.
(PAD_VARARGS_DOWN): Define.
* pa.c (function_arg_padding): Revise padding directions to make them
compatible with the 32 and 64-bit runtime architecture documentation.
(hppa_va_arg): Add code to handle variable and size zero arguments
passed by reference on TARGET_64BIT. Reformat.
(function_arg): Use a PARALLEL for BLKmode and aggregates args on
TARGET_64BIT. Use a DImode PARALLEL for BLKmode args 5 to 8 bytes
wide when !TARGET_64BIT. Move forward check for mode==VOIDmode.
Add comments.
* pa.h (MAX_PARM_BOUNDARY): Correct define for TARGET_64BIT.
(RETURN_IN_MEMORY): Return size zero types in memory.
(FUNCTION_VALUE): Return TFmode in general registers.
(MUST_PASS_IN_STACK): Define.
(FUNCTION_ARG_BOUNDARY): Simplify.
(FUNCTION_ARG_PASS_BY_REFERENCE): Pass variable and zero sized types
by reference.
(FUNCTION_ARG_CALLEE_COPIES): Define to FUNCTION_ARG_PASS_BY_REFERENCE.
2002-09-16 Richard Henderson <rth@redhat.com>
* real.c (do_fix_trunc): New.

View File

@ -4491,6 +4491,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
{
/* BLKmode, at least partly to be pushed. */
unsigned int default_align = PARM_BOUNDARY;
int excess;
rtx size_rtx;
@ -4498,6 +4499,13 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
If part is passed in registers, PARTIAL says how much
and emit_push_insn will take care of putting it there. */
#ifdef ARGS_GROW_DOWNWARD
/* When an argument is padded down, the block is not aligned to
PARM_BOUNDARY. */
if (FUNCTION_ARG_PADDING (arg->mode, TREE_TYPE (pval)) == downward)
default_align = BITS_PER_UNIT;
#endif
/* Round its size up to a multiple
of the allocation unit for arguments. */
@ -4573,7 +4581,7 @@ store_one_arg (arg, argblock, flags, variable_size, 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,
MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
partial, reg, excess, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));
@ -4582,7 +4590,7 @@ store_one_arg (arg, argblock, flags, variable_size, reg_parm_stack_space)
emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx,
MAX (PARM_BOUNDARY, TYPE_ALIGN (TREE_TYPE (pval))),
MAX (default_align, TYPE_ALIGN (TREE_TYPE (pval))),
partial, reg, excess, argblock,
ARGS_SIZE_RTX (arg->offset), reg_parm_stack_space,
ARGS_SIZE_RTX (arg->alignment_pad));

View File

@ -88,8 +88,11 @@ Boston, MA 02111-1307, USA. */
#undef STATIC_CHAIN_REGNUM
#define STATIC_CHAIN_REGNUM 31
/* Nonzero if we do not know how to pass TYPE solely in registers. */
#define MUST_PASS_IN_STACK(MODE,TYPE) \
((TYPE) != 0 \
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
|| TREE_ADDRESSABLE (TYPE)))
/* If defined, a C expression which determines whether the default
implementation of va_arg will attempt to pad down before reading the
next argument, if that argument is smaller than its aligned space as
controlled by PARM_BOUNDARY. If this macro is not defined, all such
arguments are padded down when BYTES_BIG_ENDIAN is true. We don't
want aggregrates padded down. */
#define PAD_VARARGS_DOWN (!AGGREGATE_TYPE_P (type))

View File

@ -5089,22 +5089,33 @@ function_arg_padding (mode, type)
enum machine_mode mode;
tree type;
{
int size;
if (mode == BLKmode)
if (mode == BLKmode
|| (TARGET_64BIT && type && AGGREGATE_TYPE_P (type)))
{
if (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
size = int_size_in_bytes (type) * BITS_PER_UNIT;
/* Return none if justification is not required. */
if (type
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
&& (int_size_in_bytes (type) * BITS_PER_UNIT) % PARM_BOUNDARY == 0)
return none;
/* The directions set here are ignored when a BLKmode argument larger
than a word is placed in a register. Different code is used for
the stack and registers. This makes it difficult to have a
consistent data representation for both the stack and registers.
For both runtimes, the justification and padding for arguments on
the stack and in registers should be identical. */
if (TARGET_64BIT)
/* The 64-bit runtime specifies left justification for aggregates. */
return upward;
else
return upward; /* Don't know if this is right, but */
/* same as old definition. */
/* The 32-bit runtime architecture specifies right justification.
When the argument is passed on the stack, the argument is padded
with garbage on the left. The HP compiler pads with zeros. */
return downward;
}
else
size = GET_MODE_BITSIZE (mode);
if (size < PARM_BOUNDARY)
if (GET_MODE_BITSIZE (mode) < PARM_BOUNDARY)
return downward;
else if (size % PARM_BOUNDARY)
return upward;
else
return none;
}
@ -5196,15 +5207,23 @@ rtx
hppa_va_arg (valist, type)
tree valist, type;
{
HOST_WIDE_INT align, size, ofs;
HOST_WIDE_INT size = int_size_in_bytes (type);
HOST_WIDE_INT ofs;
tree t, ptr, pptr;
if (TARGET_64BIT)
{
/* Every argument in PA64 is passed by value (including large structs).
Arguments with size greater than 8 must be aligned 0 MOD 16. */
/* Every argument in PA64 is supposed to be passed by value
(including large structs). However, as a GCC extension, we
pass zero and variable sized arguments by reference. Empty
structures are a GCC extension not supported by the HP
compilers. Thus, passing them by reference isn't likely
to conflict with the ABI. For variable sized arguments,
GCC doesn't have the infrastructure to allocate these to
registers. */
/* Arguments with a size greater than 8 must be aligned 0 MOD 16. */
size = int_size_in_bytes (type);
if (size > UNITS_PER_WORD)
{
t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
@ -5213,57 +5232,75 @@ hppa_va_arg (valist, type)
build_int_2 (-2 * UNITS_PER_WORD, -1));
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
}
return std_expand_builtin_va_arg (valist, type);
}
/* Compute the rounded size of the type. */
align = PARM_BOUNDARY / BITS_PER_UNIT;
size = int_size_in_bytes (type);
ptr = build_pointer_type (type);
/* "Large" types are passed by reference. */
if (size > 8)
{
t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
TREE_SIDE_EFFECTS (t) = 1;
pptr = build_pointer_type (ptr);
t = build1 (NOP_EXPR, pptr, t);
TREE_SIDE_EFFECTS (t) = 1;
t = build1 (INDIRECT_REF, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
else
{
t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
build_int_2 (-size, -1));
/* Copied from va-pa.h, but we probably don't need to align
to word size, since we generate and preserve that invariant. */
t = build (BIT_AND_EXPR, TREE_TYPE (valist), t,
build_int_2 ((size > 4 ? -8 : -4), -1));
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
TREE_SIDE_EFFECTS (t) = 1;
ofs = (8 - size) % 4;
if (ofs)
if (size > 0)
return std_expand_builtin_va_arg (valist, type);
else
{
t = build (PLUS_EXPR, TREE_TYPE (valist), t, build_int_2 (ofs, 0));
ptr = build_pointer_type (type);
/* Args grow upward. */
t = build (POSTINCREMENT_EXPR, TREE_TYPE (valist), valist,
build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
TREE_SIDE_EFFECTS (t) = 1;
pptr = build_pointer_type (ptr);
t = build1 (NOP_EXPR, pptr, t);
TREE_SIDE_EFFECTS (t) = 1;
t = build1 (INDIRECT_REF, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
}
else /* !TARGET_64BIT */
{
ptr = build_pointer_type (type);
t = build1 (NOP_EXPR, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
/* "Large" and variable sized types are passed by reference. */
if (size > 8 || size <= 0)
{
/* Args grow downward. */
t = build (PREDECREMENT_EXPR, TREE_TYPE (valist), valist,
build_int_2 (POINTER_SIZE / BITS_PER_UNIT, 0));
TREE_SIDE_EFFECTS (t) = 1;
pptr = build_pointer_type (ptr);
t = build1 (NOP_EXPR, pptr, t);
TREE_SIDE_EFFECTS (t) = 1;
t = build1 (INDIRECT_REF, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
else
{
t = build (PLUS_EXPR, TREE_TYPE (valist), valist,
build_int_2 (-size, -1));
/* Copied from va-pa.h, but we probably don't need to align to
word size, since we generate and preserve that invariant. */
t = build (BIT_AND_EXPR, TREE_TYPE (valist), t,
build_int_2 ((size > 4 ? -8 : -4), -1));
t = build (MODIFY_EXPR, TREE_TYPE (valist), valist, t);
TREE_SIDE_EFFECTS (t) = 1;
ofs = (8 - size) % 4;
if (ofs)
{
t = build (PLUS_EXPR, TREE_TYPE (valist), t,
build_int_2 (ofs, 0));
TREE_SIDE_EFFECTS (t) = 1;
}
t = build1 (NOP_EXPR, ptr, t);
TREE_SIDE_EFFECTS (t) = 1;
}
}
/* Calculate! */
return expand_expr (t, NULL_RTX, Pmode, EXPAND_NORMAL);
return expand_expr (t, NULL_RTX, VOIDmode, EXPAND_NORMAL);
}
@ -7446,28 +7483,32 @@ function_arg (cum, mode, type, named, incoming)
int incoming;
{
int max_arg_words = (TARGET_64BIT ? 8 : 4);
int arg_size = FUNCTION_ARG_SIZE (mode, type);
int alignment = 0;
int arg_size;
int fpr_reg_base;
int gpr_reg_base;
rtx retval;
if (mode == VOIDmode)
return NULL_RTX;
arg_size = FUNCTION_ARG_SIZE (mode, type);
/* If this arg would be passed partially or totally on the stack, then
this routine should return zero. FUNCTION_ARG_PARTIAL_NREGS will
handle arguments which are split between regs and stack slots if
the ABI mandates split arguments. */
if (! TARGET_64BIT)
{
/* If this arg would be passed partially or totally on the stack, then
this routine should return zero. FUNCTION_ARG_PARTIAL_NREGS will
handle arguments which are split between regs and stack slots if
the ABI mandates split arguments. */
if (cum->words + arg_size > max_arg_words
|| mode == VOIDmode)
/* The 32-bit ABI does not split arguments. */
if (cum->words + arg_size > max_arg_words)
return NULL_RTX;
}
else
{
if (arg_size > 1)
alignment = cum->words & 1;
if (cum->words + alignment >= max_arg_words
|| mode == VOIDmode)
if (cum->words + alignment >= max_arg_words)
return NULL_RTX;
}
@ -7488,8 +7529,11 @@ function_arg (cum, mode, type, named, incoming)
gpr_reg_base = 26 - cum->words;
fpr_reg_base = 32 + cum->words;
/* Arguments wider than one word need special treatment. */
if (arg_size > 1)
/* Arguments wider than one word and small aggregates need special
treatment. */
if (arg_size > 1
|| mode == BLKmode
|| (type && AGGREGATE_TYPE_P (type)))
{
/* Double-extended precision (80-bit), quad-precision (128-bit)
and aggregates including complex numbers are aligned on
@ -7497,7 +7541,10 @@ function_arg (cum, mode, type, named, incoming)
are associated one-to-one, with general registers r26
through r19, and also with floating-point registers fr4
through fr11. Arguments larger than one word are always
passed in general registers. */
passed in general registers.
Using a PARALLEL with a word mode register results in left
justified data on a big-endian target. */
rtx loc[8];
int i, offset = 0, ub = arg_size;
@ -7517,7 +7564,7 @@ function_arg (cum, mode, type, named, incoming)
return gen_rtx_PARALLEL (mode, gen_rtvec_v (ub, loc));
}
}
}
else
{
/* If the argument is larger than a word, then we know precisely
@ -7534,6 +7581,34 @@ function_arg (cum, mode, type, named, incoming)
gpr_reg_base = 25;
fpr_reg_base = 34;
}
/* Structures 5 to 8 bytes in size are passed in the general
registers in the same manner as other non floating-point
objects. The data is right-justified and zero-extended
to 64 bits.
This is magic. Normally, using a PARALLEL results in left
justified data on a big-endian target. However, using a
single double-word register provides the required right
justication for 5 to 8 byte structures. This has nothing
to do with the direction of padding specified for the argument.
It has to do with how the data is widened and shifted into
and from the register.
Aside from adding load_multiple and store_multiple patterns,
this is the only way that I have found to obtain right
justification of BLKmode data when it has a size greater
than one word. Splitting the operation into two SImode loads
or returning a DImode REG results in left justified data. */
if (mode == BLKmode)
{
rtx loc[1];
loc[0] = gen_rtx_EXPR_LIST (VOIDmode,
gen_rtx_REG (DImode, gpr_reg_base),
const0_rtx);
return gen_rtx_PARALLEL (mode, gen_rtvec_v (1, loc));
}
}
else
{

View File

@ -407,7 +407,7 @@ extern int target_flags;
/* Largest alignment required for any stack parameter, in bits.
Don't define this if it is equal to PARM_BOUNDARY */
#define MAX_PARM_BOUNDARY 64
#define MAX_PARM_BOUNDARY (2 * PARM_BOUNDARY)
/* Boundary (in *bits*) on which stack pointer is always aligned;
certain optimizations in combine depend on this.
@ -506,9 +506,13 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
PA64 ABI says that objects larger than 128 bits are returned in memory.
Note, int_size_in_bytes can return -1 if the size of the object is
variable or larger than the maximum value that can be expressed as
a HOST_WIDE_INT. */
a HOST_WIDE_INT. It can also return zero for an empty type. The
simplest way to handle variable and empty types is to pass them in
memory. This avoids problems in defining the boundaries of argument
slots, allocating registers, etc. */
#define RETURN_IN_MEMORY(TYPE) \
((unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) > (TARGET_64BIT ? 16 : 8))
(int_size_in_bytes (TYPE) > (TARGET_64BIT ? 16 : 8) \
|| int_size_in_bytes (TYPE) <= 0)
/* Register in which address to store a structure value
is passed to a function. */
@ -681,16 +685,18 @@ extern struct rtx_def *hppa_pic_save_rtx PARAMS ((void));
otherwise, FUNC is 0. */
/* On the HP-PA the value is found in register(s) 28(-29), unless
the mode is SF or DF. Then the value is returned in fr4 (32, ) */
the mode is SF or DF. Then the value is returned in fr4 (32). */
/* This must perform the same promotions as PROMOTE_MODE, else
PROMOTE_FUNCTION_RETURN will not work correctly. */
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
&& TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
|| POINTER_TYPE_P (VALTYPE)) \
? word_mode : TYPE_MODE (VALTYPE), \
TREE_CODE (VALTYPE) == REAL_TYPE && !TARGET_SOFT_FLOAT ? 32 : 28)
#define FUNCTION_VALUE(VALTYPE, FUNC) \
gen_rtx_REG (((INTEGRAL_TYPE_P (VALTYPE) \
&& TYPE_PRECISION (VALTYPE) < BITS_PER_WORD) \
|| POINTER_TYPE_P (VALTYPE)) \
? word_mode : TYPE_MODE (VALTYPE), \
(TREE_CODE (VALTYPE) == REAL_TYPE \
&& TYPE_MODE (VALTYPE) != TFmode \
&& !TARGET_SOFT_FLOAT) ? 32 : 28)
/* Define how to find the value returned by a library function
assuming the value has mode MODE. */
@ -745,7 +751,9 @@ struct hppa_args {int words, nargs_prototype, indirect; };
(CUM).indirect = 0, \
(CUM).nargs_prototype = 1000
/* Figure out the size in words of the function argument. */
/* Figure out the size in words of the function argument. The size
returned by this macro should always be greater than zero because
we pass variable and zero sized objects by reference. */
#define FUNCTION_ARG_SIZE(MODE, TYPE) \
((((MODE) != BLKmode \
@ -817,6 +825,12 @@ struct hppa_args {int words, nargs_prototype, indirect; };
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
function_arg (&CUM, MODE, TYPE, NAMED, 0)
/* Nonzero if we do not know how to pass TYPE solely in registers. */
#define MUST_PASS_IN_STACK(MODE,TYPE) \
((TYPE) != 0 \
&& (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \
|| TREE_ADDRESSABLE (TYPE)))
#define FUNCTION_INCOMING_ARG(CUM, MODE, TYPE, NAMED) \
function_arg (&CUM, MODE, TYPE, NAMED, 1)
@ -833,33 +847,37 @@ struct hppa_args {int words, nargs_prototype, indirect; };
bits, of an argument with the specified mode and type. If it is
not defined, `PARM_BOUNDARY' is used for all arguments. */
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
(((TYPE) != 0) \
? ((integer_zerop (TYPE_SIZE (TYPE)) \
|| ! TREE_CONSTANT (TYPE_SIZE (TYPE))) \
? BITS_PER_UNIT \
: (((int_size_in_bytes (TYPE)) + UNITS_PER_WORD - 1) \
/ UNITS_PER_WORD) * BITS_PER_WORD) \
: ((GET_MODE_ALIGNMENT(MODE) <= PARM_BOUNDARY) \
? PARM_BOUNDARY : GET_MODE_ALIGNMENT(MODE)))
/* Arguments larger than one word are double word aligned. */
/* Arguments larger than eight bytes are passed by invisible reference */
#define FUNCTION_ARG_BOUNDARY(MODE, TYPE) \
(((TYPE) \
? (integer_zerop (TYPE_SIZE (TYPE)) \
|| !TREE_CONSTANT (TYPE_SIZE (TYPE)) \
|| int_size_in_bytes (TYPE) <= UNITS_PER_WORD) \
: GET_MODE_SIZE(MODE) <= UNITS_PER_WORD) \
? PARM_BOUNDARY : MAX_PARM_BOUNDARY)
/* PA64 does not pass anything by invisible reference. */
/* In the 32-bit runtime, arguments larger than eight bytes are passed
by invisible reference. As a GCC extension, we also pass anything
with a zero or variable size by reference.
The 64-bit runtime does not describe passing any types by invisible
reference. The internals of GCC can't currently handle passing
empty structures, and zero or variable length arrays when they are
not passed entirely on the stack or by reference. Thus, as a GCC
extension, we pass these types by reference. The HP compiler doesn't
support these types, so hopefully there shouldn't be any compatibility
issues. This may have to be revisited when HP releases a C99 compiler
or updates the ABI. */
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM, MODE, TYPE, NAMED) \
(TARGET_64BIT \
? 0 \
: (((TYPE) && int_size_in_bytes (TYPE) > 8) \
? ((TYPE) && int_size_in_bytes (TYPE) <= 0) \
: (((TYPE) && (int_size_in_bytes (TYPE) > 8 \
|| int_size_in_bytes (TYPE) <= 0)) \
|| ((MODE) && GET_MODE_SIZE (MODE) > 8)))
/* PA64 does not pass anything by invisible reference.
This should be undef'ed for 64bit, but we'll see if this works. The
problem is that we can't test TARGET_64BIT from the preprocessor. */
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
(TARGET_64BIT \
? 0 \
: (((TYPE) && int_size_in_bytes (TYPE) > 8) \
|| ((MODE) && GET_MODE_SIZE (MODE) > 8)))
#define FUNCTION_ARG_CALLEE_COPIES(CUM, MODE, TYPE, NAMED) \
FUNCTION_ARG_PASS_BY_REFERENCE (CUM, MODE, TYPE, NAMED)
extern GTY(()) rtx hppa_compare_op0;

View File

@ -255,10 +255,8 @@ static int instantiate_virtual_regs_1 PARAMS ((rtx *, rtx, int));
static void delete_handlers PARAMS ((void));
static void pad_to_arg_alignment PARAMS ((struct args_size *, int,
struct args_size *));
#ifndef ARGS_GROW_DOWNWARD
static void pad_below PARAMS ((struct args_size *, enum machine_mode,
tree));
#endif
static rtx round_trampoline_addr PARAMS ((rtx));
static rtx adjust_trampoline_addr PARAMS ((rtx));
static tree *identify_blocks_1 PARAMS ((rtx, tree *, tree *, tree *));
@ -5244,6 +5242,9 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
= type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode));
enum direction where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
int boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
#ifdef ARGS_GROW_DOWNWARD
tree s2 = sizetree;
#endif
#ifdef REG_PARM_STACK_SPACE
/* If we have found a stack parm before we reach the end of the
@ -5289,13 +5290,20 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
offset_ptr->constant = -initial_offset_ptr->constant;
offset_ptr->var = 0;
}
if (where_pad != none
&& (!host_integerp (sizetree, 1)
|| (tree_low_cst (sizetree, 1) * BITS_PER_UNIT) % PARM_BOUNDARY))
sizetree = round_up (sizetree, PARM_BOUNDARY / BITS_PER_UNIT);
SUB_PARM_SIZE (*offset_ptr, sizetree);
if (where_pad != downward)
s2 = round_up (s2, PARM_BOUNDARY / BITS_PER_UNIT);
SUB_PARM_SIZE (*offset_ptr, s2);
if (!in_regs
#ifdef REG_PARM_STACK_SPACE
|| REG_PARM_STACK_SPACE (fndecl) > 0
#endif
)
pad_to_arg_alignment (offset_ptr, boundary, alignment_pad);
if (initial_offset_ptr->var)
arg_size_ptr->var = size_binop (MINUS_EXPR,
size_binop (MINUS_EXPR,
@ -5307,6 +5315,13 @@ locate_and_pad_parm (passed_mode, type, in_regs, fndecl,
arg_size_ptr->constant = (-initial_offset_ptr->constant
- offset_ptr->constant);
/* Pad_below needs the pre-rounded size to know how much to pad below.
We only pad parameters which are not in registers as they have their
padding done elsewhere. */
if (where_pad == downward
&& !in_regs)
pad_below (offset_ptr, passed_mode, sizetree);
#else /* !ARGS_GROW_DOWNWARD */
if (!in_regs
#ifdef REG_PARM_STACK_SPACE
@ -5392,7 +5407,6 @@ pad_to_arg_alignment (offset_ptr, boundary, alignment_pad)
}
}
#ifndef ARGS_GROW_DOWNWARD
static void
pad_below (offset_ptr, passed_mode, sizetree)
struct args_size *offset_ptr;
@ -5420,7 +5434,6 @@ pad_below (offset_ptr, passed_mode, sizetree)
}
}
}
#endif
/* Walk the tree of blocks describing the binding levels within a function
and warn about uninitialized variables.