mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-07 19:27:40 +08:00
calls.c (initialize_argument_information): New function extracted from expand_call.
* calls.c (initialize_argument_information): New function extracted from expand_call. (expand_call): Use initialize_argument_information. Remove variables which are no longer used due to cleanups. From-SVN: r25416
This commit is contained in:
parent
c55310ab51
commit
d7cdf1138e
@ -5,6 +5,11 @@ Wed Feb 24 17:47:28 1999 Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
Wed Feb 24 14:03:54 1999 Jeffrey A Law (law@cygnus.com)
|
||||
|
||||
* calls.c (initialize_argument_information): New function extracted
|
||||
from expand_call.
|
||||
(expand_call): Use initialize_argument_information. Remove variables
|
||||
which are no longer used due to cleanups.
|
||||
|
||||
* calls.c (compute_argument_block_size): New function, extracted from
|
||||
expand_calls.
|
||||
(expand_calls): Use compute_argument_block_size. Delete
|
||||
|
530
gcc/calls.c
530
gcc/calls.c
@ -145,6 +145,13 @@ static void precompute_arguments PROTO ((int, int, int,
|
||||
struct args_size *));
|
||||
static int compute_argument_block_size PROTO ((int,
|
||||
struct args_size *));
|
||||
static void initialize_argument_information PROTO ((int,
|
||||
struct arg_data *,
|
||||
struct args_size *,
|
||||
int, tree, tree,
|
||||
CUMULATIVE_ARGS,
|
||||
int, rtx *, int *,
|
||||
int *, int *));
|
||||
|
||||
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
|
||||
static rtx save_fixed_argument_area PROTO ((int, rtx, int *, int *));
|
||||
@ -830,6 +837,287 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
|
||||
}
|
||||
}
|
||||
|
||||
/* Fill in ARGS_SIZE and ARGS array based on the parameters found in
|
||||
ACTPARMS.
|
||||
|
||||
NUM_ACTUALS is the total number of parameters.
|
||||
|
||||
N_NAMED_ARGS is the total number of named arguments.
|
||||
|
||||
FNDECL is the tree code for the target of this call (if known)
|
||||
|
||||
ARGS_SO_FAR holds state needed by the target to know where to place
|
||||
the next argument.
|
||||
|
||||
REG_PARM_STACK_SPACE is the number of bytes of stack space reserved
|
||||
for arguments which are passed in registers.
|
||||
|
||||
OLD_STACK_LEVEL is a pointer to an rtx which olds the old stack level
|
||||
and may be modified by this routine.
|
||||
|
||||
OLD_PENDING_ADJ, MUST_PREALLOCATE and IS_CONST are pointers to integer
|
||||
flags which may may be modified by this routine. */
|
||||
|
||||
static void
|
||||
initialize_argument_information (num_actuals, args, args_size, n_named_args,
|
||||
actparms, fndecl, args_so_far,
|
||||
reg_parm_stack_space, old_stack_level,
|
||||
old_pending_adj, must_preallocate, is_const)
|
||||
int num_actuals;
|
||||
struct arg_data *args;
|
||||
struct args_size *args_size;
|
||||
int n_named_args;
|
||||
tree actparms;
|
||||
tree fndecl;
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
int reg_parm_stack_space;
|
||||
rtx *old_stack_level;
|
||||
int *old_pending_adj;
|
||||
int *must_preallocate;
|
||||
int *is_const;
|
||||
{
|
||||
/* 1 if scanning parms front to back, -1 if scanning back to front. */
|
||||
int inc;
|
||||
|
||||
/* Count arg position in order args appear. */
|
||||
int argpos;
|
||||
|
||||
int i;
|
||||
tree p;
|
||||
|
||||
args_size->constant = 0;
|
||||
args_size->var = 0;
|
||||
|
||||
/* In this loop, we consider args in the order they are written.
|
||||
We fill up ARGS from the front or from the back if necessary
|
||||
so that in any case the first arg to be pushed ends up at the front. */
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
i = num_actuals - 1, inc = -1;
|
||||
/* In this case, must reverse order of args
|
||||
so that we compute and push the last arg first. */
|
||||
#else
|
||||
i = 0, inc = 1;
|
||||
#endif
|
||||
|
||||
/* I counts args in order (to be) pushed; ARGPOS counts in order written. */
|
||||
for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
|
||||
{
|
||||
tree type = TREE_TYPE (TREE_VALUE (p));
|
||||
int unsignedp;
|
||||
enum machine_mode mode;
|
||||
|
||||
args[i].tree_value = TREE_VALUE (p);
|
||||
|
||||
/* Replace erroneous argument with constant zero. */
|
||||
if (type == error_mark_node || TYPE_SIZE (type) == 0)
|
||||
args[i].tree_value = integer_zero_node, type = integer_type_node;
|
||||
|
||||
/* If TYPE is a transparent union, pass things the way we would
|
||||
pass the first field of the union. We have already verified that
|
||||
the modes are the same. */
|
||||
if (TYPE_TRANSPARENT_UNION (type))
|
||||
type = TREE_TYPE (TYPE_FIELDS (type));
|
||||
|
||||
/* Decide where to pass this arg.
|
||||
|
||||
args[i].reg is nonzero if all or part is passed in registers.
|
||||
|
||||
args[i].partial is nonzero if part but not all is passed in registers,
|
||||
and the exact value says how many words are passed in registers.
|
||||
|
||||
args[i].pass_on_stack is nonzero if the argument must at least be
|
||||
computed on the stack. It may then be loaded back into registers
|
||||
if args[i].reg is nonzero.
|
||||
|
||||
These decisions are driven by the FUNCTION_... macros and must agree
|
||||
with those made by function.c. */
|
||||
|
||||
/* See if this argument should be passed by invisible reference. */
|
||||
if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
|
||||
&& contains_placeholder_p (TYPE_SIZE (type)))
|
||||
|| TREE_ADDRESSABLE (type)
|
||||
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|
||||
|| FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),
|
||||
type, argpos < n_named_args)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* If we're compiling a thunk, pass through invisible
|
||||
references instead of making a copy. */
|
||||
if (current_function_is_thunk
|
||||
#ifdef FUNCTION_ARG_CALLEE_COPIES
|
||||
|| (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
|
||||
type, argpos < n_named_args)
|
||||
/* If it's in a register, we must make a copy of it too. */
|
||||
/* ??? Is this a sufficient test? Is there a better one? */
|
||||
&& !(TREE_CODE (args[i].tree_value) == VAR_DECL
|
||||
&& REG_P (DECL_RTL (args[i].tree_value)))
|
||||
&& ! TREE_ADDRESSABLE (type))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* C++ uses a TARGET_EXPR to indicate that we want to make a
|
||||
new object from the argument. If we are passing by
|
||||
invisible reference, the callee will do that for us, so we
|
||||
can strip off the TARGET_EXPR. This is not always safe,
|
||||
but it is safe in the only case where this is a useful
|
||||
optimization; namely, when the argument is a plain object.
|
||||
In that case, the frontend is just asking the backend to
|
||||
make a bitwise copy of the argument. */
|
||||
|
||||
if (TREE_CODE (args[i].tree_value) == TARGET_EXPR
|
||||
&& (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND
|
||||
(args[i].tree_value, 1)))
|
||||
== 'd')
|
||||
&& ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1))))
|
||||
args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1);
|
||||
|
||||
args[i].tree_value = build1 (ADDR_EXPR,
|
||||
build_pointer_type (type),
|
||||
args[i].tree_value);
|
||||
type = build_pointer_type (type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We make a copy of the object and pass the address to the
|
||||
function being called. */
|
||||
rtx copy;
|
||||
|
||||
if (TYPE_SIZE (type) == 0
|
||||
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
|
||||
|| (flag_stack_check && ! STACK_CHECK_BUILTIN
|
||||
&& (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0
|
||||
|| (TREE_INT_CST_LOW (TYPE_SIZE (type))
|
||||
> STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
|
||||
{
|
||||
/* This is a variable-sized object. Make space on the stack
|
||||
for it. */
|
||||
rtx size_rtx = expr_size (TREE_VALUE (p));
|
||||
|
||||
if (*old_stack_level == 0)
|
||||
{
|
||||
emit_stack_save (SAVE_BLOCK, old_stack_level, NULL_RTX);
|
||||
*old_pending_adj = pending_stack_adjust;
|
||||
pending_stack_adjust = 0;
|
||||
}
|
||||
|
||||
copy = gen_rtx_MEM (BLKmode,
|
||||
allocate_dynamic_stack_space (size_rtx,
|
||||
NULL_RTX,
|
||||
TYPE_ALIGN (type)));
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = int_size_in_bytes (type);
|
||||
copy = assign_stack_temp (TYPE_MODE (type), size, 0);
|
||||
}
|
||||
|
||||
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
|
||||
|
||||
store_expr (args[i].tree_value, copy, 0);
|
||||
*is_const = 0;
|
||||
|
||||
args[i].tree_value = build1 (ADDR_EXPR,
|
||||
build_pointer_type (type),
|
||||
make_tree (type, copy));
|
||||
type = build_pointer_type (type);
|
||||
}
|
||||
}
|
||||
|
||||
mode = TYPE_MODE (type);
|
||||
unsignedp = TREE_UNSIGNED (type);
|
||||
|
||||
#ifdef PROMOTE_FUNCTION_ARGS
|
||||
mode = promote_mode (type, mode, &unsignedp, 1);
|
||||
#endif
|
||||
|
||||
args[i].unsignedp = unsignedp;
|
||||
args[i].mode = mode;
|
||||
args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
|
||||
argpos < n_named_args);
|
||||
#ifdef FUNCTION_ARG_PARTIAL_NREGS
|
||||
if (args[i].reg)
|
||||
args[i].partial
|
||||
= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
|
||||
argpos < n_named_args);
|
||||
#endif
|
||||
|
||||
args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
|
||||
|
||||
/* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),
|
||||
it means that we are to pass this arg in the register(s) designated
|
||||
by the PARALLEL, but also to pass it in the stack. */
|
||||
if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL
|
||||
&& XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)
|
||||
args[i].pass_on_stack = 1;
|
||||
|
||||
/* If this is an addressable type, we must preallocate the stack
|
||||
since we must evaluate the object into its final location.
|
||||
|
||||
If this is to be passed in both registers and the stack, it is simpler
|
||||
to preallocate. */
|
||||
if (TREE_ADDRESSABLE (type)
|
||||
|| (args[i].pass_on_stack && args[i].reg != 0))
|
||||
*must_preallocate = 1;
|
||||
|
||||
/* If this is an addressable type, we cannot pre-evaluate it. Thus,
|
||||
we cannot consider this function call constant. */
|
||||
if (TREE_ADDRESSABLE (type))
|
||||
*is_const = 0;
|
||||
|
||||
/* Compute the stack-size of this argument. */
|
||||
if (args[i].reg == 0 || args[i].partial != 0
|
||||
|| reg_parm_stack_space > 0
|
||||
|| args[i].pass_on_stack)
|
||||
locate_and_pad_parm (mode, type,
|
||||
#ifdef STACK_PARMS_IN_REG_PARM_AREA
|
||||
1,
|
||||
#else
|
||||
args[i].reg != 0,
|
||||
#endif
|
||||
fndecl, args_size, &args[i].offset,
|
||||
&args[i].size);
|
||||
|
||||
#ifndef ARGS_GROW_DOWNWARD
|
||||
args[i].slot_offset = *args_size;
|
||||
#endif
|
||||
|
||||
/* If a part of the arg was put into registers,
|
||||
don't include that part in the amount pushed. */
|
||||
if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack)
|
||||
args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)
|
||||
/ (PARM_BOUNDARY / BITS_PER_UNIT)
|
||||
* (PARM_BOUNDARY / BITS_PER_UNIT));
|
||||
|
||||
/* Update ARGS_SIZE, the total stack space for args so far. */
|
||||
|
||||
args_size->constant += args[i].size.constant;
|
||||
if (args[i].size.var)
|
||||
{
|
||||
ADD_PARM_SIZE (*args_size, args[i].size.var);
|
||||
}
|
||||
|
||||
/* Since the slot offset points to the bottom of the slot,
|
||||
we must record it after incrementing if the args grow down. */
|
||||
#ifdef ARGS_GROW_DOWNWARD
|
||||
args[i].slot_offset = *args_size;
|
||||
|
||||
args[i].slot_offset.constant = -args_size->constant;
|
||||
if (args_size->var)
|
||||
{
|
||||
SUB_PARM_SIZE (args[i].slot_offset, args_size->var);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Increment ARGS_SO_FAR, which has info about which arg-registers
|
||||
have been used, etc. */
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
|
||||
argpos < n_named_args);
|
||||
}
|
||||
}
|
||||
|
||||
/* Update ARGS_SIZE to contain the total size for the argument block.
|
||||
Return the original constant component of the argument block's size.
|
||||
|
||||
@ -1071,8 +1359,6 @@ expand_call (exp, target, ignore)
|
||||
/* Number of named args. Args after this are anonymous ones
|
||||
and they must all go on the stack. */
|
||||
int n_named_args;
|
||||
/* Count arg position in order args appear. */
|
||||
int argpos;
|
||||
|
||||
/* Vector of information about each argument.
|
||||
Arguments are numbered in the order they will be pushed,
|
||||
@ -1104,8 +1390,6 @@ expand_call (exp, target, ignore)
|
||||
/* Size of the stack reserved for parameter registers. */
|
||||
int reg_parm_stack_space = 0;
|
||||
|
||||
/* 1 if scanning parms front to back, -1 if scanning back to front. */
|
||||
int inc;
|
||||
/* Address of space preallocated for stack parms
|
||||
(on machines that lack push insns), or 0 if space not preallocated. */
|
||||
rtx argblock = 0;
|
||||
@ -1477,237 +1761,13 @@ expand_call (exp, target, ignore)
|
||||
args = (struct arg_data *) alloca (num_actuals * sizeof (struct arg_data));
|
||||
bzero ((char *) args, num_actuals * sizeof (struct arg_data));
|
||||
|
||||
args_size.constant = 0;
|
||||
args_size.var = 0;
|
||||
|
||||
/* In this loop, we consider args in the order they are written.
|
||||
We fill up ARGS from the front or from the back if necessary
|
||||
so that in any case the first arg to be pushed ends up at the front. */
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
i = num_actuals - 1, inc = -1;
|
||||
/* In this case, must reverse order of args
|
||||
so that we compute and push the last arg first. */
|
||||
#else
|
||||
i = 0, inc = 1;
|
||||
#endif
|
||||
|
||||
/* I counts args in order (to be) pushed; ARGPOS counts in order written. */
|
||||
for (p = actparms, argpos = 0; p; p = TREE_CHAIN (p), i += inc, argpos++)
|
||||
{
|
||||
tree type = TREE_TYPE (TREE_VALUE (p));
|
||||
int unsignedp;
|
||||
enum machine_mode mode;
|
||||
|
||||
args[i].tree_value = TREE_VALUE (p);
|
||||
|
||||
/* Replace erroneous argument with constant zero. */
|
||||
if (type == error_mark_node || TYPE_SIZE (type) == 0)
|
||||
args[i].tree_value = integer_zero_node, type = integer_type_node;
|
||||
|
||||
/* If TYPE is a transparent union, pass things the way we would
|
||||
pass the first field of the union. We have already verified that
|
||||
the modes are the same. */
|
||||
if (TYPE_TRANSPARENT_UNION (type))
|
||||
type = TREE_TYPE (TYPE_FIELDS (type));
|
||||
|
||||
/* Decide where to pass this arg.
|
||||
|
||||
args[i].reg is nonzero if all or part is passed in registers.
|
||||
|
||||
args[i].partial is nonzero if part but not all is passed in registers,
|
||||
and the exact value says how many words are passed in registers.
|
||||
|
||||
args[i].pass_on_stack is nonzero if the argument must at least be
|
||||
computed on the stack. It may then be loaded back into registers
|
||||
if args[i].reg is nonzero.
|
||||
|
||||
These decisions are driven by the FUNCTION_... macros and must agree
|
||||
with those made by function.c. */
|
||||
|
||||
/* See if this argument should be passed by invisible reference. */
|
||||
if ((TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
|
||||
&& contains_placeholder_p (TYPE_SIZE (type)))
|
||||
|| TREE_ADDRESSABLE (type)
|
||||
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|
||||
|| FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, TYPE_MODE (type),
|
||||
type, argpos < n_named_args)
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* If we're compiling a thunk, pass through invisible
|
||||
references instead of making a copy. */
|
||||
if (current_function_is_thunk
|
||||
#ifdef FUNCTION_ARG_CALLEE_COPIES
|
||||
|| (FUNCTION_ARG_CALLEE_COPIES (args_so_far, TYPE_MODE (type),
|
||||
type, argpos < n_named_args)
|
||||
/* If it's in a register, we must make a copy of it too. */
|
||||
/* ??? Is this a sufficient test? Is there a better one? */
|
||||
&& !(TREE_CODE (args[i].tree_value) == VAR_DECL
|
||||
&& REG_P (DECL_RTL (args[i].tree_value)))
|
||||
&& ! TREE_ADDRESSABLE (type))
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* C++ uses a TARGET_EXPR to indicate that we want to make a
|
||||
new object from the argument. If we are passing by
|
||||
invisible reference, the callee will do that for us, so we
|
||||
can strip off the TARGET_EXPR. This is not always safe,
|
||||
but it is safe in the only case where this is a useful
|
||||
optimization; namely, when the argument is a plain object.
|
||||
In that case, the frontend is just asking the backend to
|
||||
make a bitwise copy of the argument. */
|
||||
|
||||
if (TREE_CODE (args[i].tree_value) == TARGET_EXPR
|
||||
&& (TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND
|
||||
(args[i].tree_value, 1)))
|
||||
== 'd')
|
||||
&& ! REG_P (DECL_RTL (TREE_OPERAND (args[i].tree_value, 1))))
|
||||
args[i].tree_value = TREE_OPERAND (args[i].tree_value, 1);
|
||||
|
||||
args[i].tree_value = build1 (ADDR_EXPR,
|
||||
build_pointer_type (type),
|
||||
args[i].tree_value);
|
||||
type = build_pointer_type (type);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We make a copy of the object and pass the address to the
|
||||
function being called. */
|
||||
rtx copy;
|
||||
|
||||
if (TYPE_SIZE (type) == 0
|
||||
|| TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST
|
||||
|| (flag_stack_check && ! STACK_CHECK_BUILTIN
|
||||
&& (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0
|
||||
|| (TREE_INT_CST_LOW (TYPE_SIZE (type))
|
||||
> STACK_CHECK_MAX_VAR_SIZE * BITS_PER_UNIT))))
|
||||
{
|
||||
/* This is a variable-sized object. Make space on the stack
|
||||
for it. */
|
||||
rtx size_rtx = expr_size (TREE_VALUE (p));
|
||||
|
||||
if (old_stack_level == 0)
|
||||
{
|
||||
emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
|
||||
old_pending_adj = pending_stack_adjust;
|
||||
pending_stack_adjust = 0;
|
||||
}
|
||||
|
||||
copy = gen_rtx_MEM (BLKmode,
|
||||
allocate_dynamic_stack_space (size_rtx,
|
||||
NULL_RTX,
|
||||
TYPE_ALIGN (type)));
|
||||
}
|
||||
else
|
||||
{
|
||||
int size = int_size_in_bytes (type);
|
||||
copy = assign_stack_temp (TYPE_MODE (type), size, 0);
|
||||
}
|
||||
|
||||
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
|
||||
|
||||
store_expr (args[i].tree_value, copy, 0);
|
||||
is_const = 0;
|
||||
|
||||
args[i].tree_value = build1 (ADDR_EXPR,
|
||||
build_pointer_type (type),
|
||||
make_tree (type, copy));
|
||||
type = build_pointer_type (type);
|
||||
}
|
||||
}
|
||||
|
||||
mode = TYPE_MODE (type);
|
||||
unsignedp = TREE_UNSIGNED (type);
|
||||
|
||||
#ifdef PROMOTE_FUNCTION_ARGS
|
||||
mode = promote_mode (type, mode, &unsignedp, 1);
|
||||
#endif
|
||||
|
||||
args[i].unsignedp = unsignedp;
|
||||
args[i].mode = mode;
|
||||
args[i].reg = FUNCTION_ARG (args_so_far, mode, type,
|
||||
argpos < n_named_args);
|
||||
#ifdef FUNCTION_ARG_PARTIAL_NREGS
|
||||
if (args[i].reg)
|
||||
args[i].partial
|
||||
= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, type,
|
||||
argpos < n_named_args);
|
||||
#endif
|
||||
|
||||
args[i].pass_on_stack = MUST_PASS_IN_STACK (mode, type);
|
||||
|
||||
/* If FUNCTION_ARG returned a (parallel [(expr_list (nil) ...) ...]),
|
||||
it means that we are to pass this arg in the register(s) designated
|
||||
by the PARALLEL, but also to pass it in the stack. */
|
||||
if (args[i].reg && GET_CODE (args[i].reg) == PARALLEL
|
||||
&& XEXP (XVECEXP (args[i].reg, 0, 0), 0) == 0)
|
||||
args[i].pass_on_stack = 1;
|
||||
|
||||
/* If this is an addressable type, we must preallocate the stack
|
||||
since we must evaluate the object into its final location.
|
||||
|
||||
If this is to be passed in both registers and the stack, it is simpler
|
||||
to preallocate. */
|
||||
if (TREE_ADDRESSABLE (type)
|
||||
|| (args[i].pass_on_stack && args[i].reg != 0))
|
||||
must_preallocate = 1;
|
||||
|
||||
/* If this is an addressable type, we cannot pre-evaluate it. Thus,
|
||||
we cannot consider this function call constant. */
|
||||
if (TREE_ADDRESSABLE (type))
|
||||
is_const = 0;
|
||||
|
||||
/* Compute the stack-size of this argument. */
|
||||
if (args[i].reg == 0 || args[i].partial != 0
|
||||
|| reg_parm_stack_space > 0
|
||||
|| args[i].pass_on_stack)
|
||||
locate_and_pad_parm (mode, type,
|
||||
#ifdef STACK_PARMS_IN_REG_PARM_AREA
|
||||
1,
|
||||
#else
|
||||
args[i].reg != 0,
|
||||
#endif
|
||||
fndecl, &args_size, &args[i].offset,
|
||||
&args[i].size);
|
||||
|
||||
#ifndef ARGS_GROW_DOWNWARD
|
||||
args[i].slot_offset = args_size;
|
||||
#endif
|
||||
|
||||
/* If a part of the arg was put into registers,
|
||||
don't include that part in the amount pushed. */
|
||||
if (reg_parm_stack_space == 0 && ! args[i].pass_on_stack)
|
||||
args[i].size.constant -= ((args[i].partial * UNITS_PER_WORD)
|
||||
/ (PARM_BOUNDARY / BITS_PER_UNIT)
|
||||
* (PARM_BOUNDARY / BITS_PER_UNIT));
|
||||
|
||||
/* Update ARGS_SIZE, the total stack space for args so far. */
|
||||
|
||||
args_size.constant += args[i].size.constant;
|
||||
if (args[i].size.var)
|
||||
{
|
||||
ADD_PARM_SIZE (args_size, args[i].size.var);
|
||||
}
|
||||
|
||||
/* Since the slot offset points to the bottom of the slot,
|
||||
we must record it after incrementing if the args grow down. */
|
||||
#ifdef ARGS_GROW_DOWNWARD
|
||||
args[i].slot_offset = args_size;
|
||||
|
||||
args[i].slot_offset.constant = -args_size.constant;
|
||||
if (args_size.var)
|
||||
{
|
||||
SUB_PARM_SIZE (args[i].slot_offset, args_size.var);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Increment ARGS_SO_FAR, which has info about which arg-registers
|
||||
have been used, etc. */
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, TYPE_MODE (type), type,
|
||||
argpos < n_named_args);
|
||||
}
|
||||
/* Build up entries inthe ARGS array, compute the size of the arguments
|
||||
into ARGS_SIZE, etc. */
|
||||
initialize_argument_information (num_actuals, args, &args_size, n_named_args,
|
||||
actparms, fndecl, args_so_far,
|
||||
reg_parm_stack_space, &old_stack_level,
|
||||
&old_pending_adj, &must_preallocate,
|
||||
&is_const);
|
||||
|
||||
#ifdef FINAL_REG_PARM_STACK_SPACE
|
||||
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
|
||||
|
Loading…
Reference in New Issue
Block a user