Include gvarargs.h.
Add prototypes to forward declarations and declare static functions. (prepare_call_address, emit_call_1): Now static. (emit_library_call, emit_library_call_value): Move to here. From-SVN: r3848
This commit is contained in:
parent
b587ed6660
commit
322e3e3420
611
gcc/calls.c
611
gcc/calls.c
|
@ -22,6 +22,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#include "tree.h"
|
||||
#include "flags.h"
|
||||
#include "expr.h"
|
||||
#include "gvarargs.h"
|
||||
#include "insn-flags.h"
|
||||
|
||||
/* Decide whether a function's arguments should be processed
|
||||
|
@ -117,8 +118,12 @@ static int highest_outgoing_arg_in_use;
|
|||
int stack_arg_under_construction;
|
||||
#endif
|
||||
|
||||
static void store_one_arg ();
|
||||
extern enum machine_mode mode_for_size ();
|
||||
static int calls_function PROTO((tree, int));
|
||||
static rtx prepare_call_address PROTO((rtx, tree, rtx *));
|
||||
static void emit_call_1 PROTO((rtx, tree, int, int, rtx, rtx, int,
|
||||
rtx, int));
|
||||
static void store_one_arg PROTO ((struct arg_data *, rtx, int, int,
|
||||
tree, int));
|
||||
|
||||
/* If WHICH is 1, return 1 if EXP contains a call to the built-in function
|
||||
`alloca'.
|
||||
|
@ -213,7 +218,7 @@ calls_function (exp, which)
|
|||
to which a USE of the static chain
|
||||
register should be added, if required. */
|
||||
|
||||
rtx
|
||||
static rtx
|
||||
prepare_call_address (funexp, fndecl, use_insns)
|
||||
rtx funexp;
|
||||
tree fndecl;
|
||||
|
@ -293,7 +298,7 @@ prepare_call_address (funexp, fndecl, use_insns)
|
|||
|
||||
IS_CONST is true if this is a `const' call. */
|
||||
|
||||
void
|
||||
static void
|
||||
emit_call_1 (funexp, funtype, stack_size, struct_value_size, next_arg_reg,
|
||||
valreg, old_inhibit_defer_pop, use_insns, is_const)
|
||||
rtx funexp;
|
||||
|
@ -1931,6 +1936,604 @@ expand_call (exp, target, ignore)
|
|||
return target;
|
||||
}
|
||||
|
||||
/* Output a library call to function FUN (a SYMBOL_REF rtx)
|
||||
(emitting the queue unless NO_QUEUE is nonzero),
|
||||
for a value of mode OUTMODE,
|
||||
with NARGS different arguments, passed as alternating rtx values
|
||||
and machine_modes to convert them to.
|
||||
The rtx values should have been passed through protect_from_queue already.
|
||||
|
||||
NO_QUEUE will be true if and only if the library call is a `const' call
|
||||
which will be enclosed in REG_LIBCALL/REG_RETVAL notes; it is equivalent
|
||||
to the variable is_const in expand_call.
|
||||
|
||||
NO_QUEUE must be true for const calls, because if it isn't, then
|
||||
any pending increment will be emitted between REG_LIBCALL/REG_RETVAL notes,
|
||||
and will be lost if the libcall sequence is optimized away.
|
||||
|
||||
NO_QUEUE must be false for non-const calls, because if it isn't, the
|
||||
call insn will have its CONST_CALL_P bit set, and it will be incorrectly
|
||||
optimized. For instance, the instruction scheduler may incorrectly
|
||||
move memory references across the non-const call. */
|
||||
|
||||
void
|
||||
emit_library_call (va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list p;
|
||||
/* Total size in bytes of all the stack-parms scanned so far. */
|
||||
struct args_size args_size;
|
||||
/* Size of arguments before any adjustments (such as rounding). */
|
||||
struct args_size original_args_size;
|
||||
register int argnum;
|
||||
enum machine_mode outmode;
|
||||
int nargs;
|
||||
rtx fun;
|
||||
rtx orgfun;
|
||||
int inc;
|
||||
int count;
|
||||
rtx argblock = 0;
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
|
||||
struct args_size offset; struct args_size size; };
|
||||
struct arg *argvec;
|
||||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||
int no_queue = 0;
|
||||
rtx use_insns;
|
||||
|
||||
va_start (p);
|
||||
orgfun = fun = va_arg (p, rtx);
|
||||
no_queue = va_arg (p, int);
|
||||
outmode = va_arg (p, enum machine_mode);
|
||||
nargs = va_arg (p, int);
|
||||
|
||||
/* Copy all the libcall-arguments out of the varargs data
|
||||
and into a vector ARGVEC.
|
||||
|
||||
Compute how to pass each argument. We only support a very small subset
|
||||
of the full argument passing conventions to limit complexity here since
|
||||
library functions shouldn't have many args. */
|
||||
|
||||
argvec = (struct arg *) alloca (nargs * sizeof (struct arg));
|
||||
|
||||
INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
|
||||
|
||||
args_size.constant = 0;
|
||||
args_size.var = 0;
|
||||
|
||||
for (count = 0; count < nargs; count++)
|
||||
{
|
||||
rtx val = va_arg (p, rtx);
|
||||
enum machine_mode mode = va_arg (p, enum machine_mode);
|
||||
|
||||
/* We cannot convert the arg value to the mode the library wants here;
|
||||
must do it earlier where we know the signedness of the arg. */
|
||||
if (mode == BLKmode
|
||||
|| (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
|
||||
abort ();
|
||||
|
||||
/* On some machines, there's no way to pass a float to a library fcn.
|
||||
Pass it as a double instead. */
|
||||
#ifdef LIBGCC_NEEDS_DOUBLE
|
||||
if (LIBGCC_NEEDS_DOUBLE && mode == SFmode)
|
||||
val = convert_to_mode (DFmode, val, 0), mode = DFmode;
|
||||
#endif
|
||||
|
||||
/* There's no need to call protect_from_queue, because
|
||||
either emit_move_insn or emit_push_insn will do that. */
|
||||
|
||||
/* Make sure it is a reasonable operand for a move or push insn. */
|
||||
if (GET_CODE (val) != REG && GET_CODE (val) != MEM
|
||||
&& ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
|
||||
val = force_operand (val, NULL_RTX);
|
||||
|
||||
argvec[count].value = val;
|
||||
argvec[count].mode = mode;
|
||||
|
||||
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|
||||
if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
|
||||
if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
|
||||
abort ();
|
||||
#ifdef FUNCTION_ARG_PARTIAL_NREGS
|
||||
argvec[count].partial
|
||||
= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1);
|
||||
#else
|
||||
argvec[count].partial = 0;
|
||||
#endif
|
||||
|
||||
locate_and_pad_parm (mode, NULL_TREE,
|
||||
argvec[count].reg && argvec[count].partial == 0,
|
||||
NULL_TREE, &args_size, &argvec[count].offset,
|
||||
&argvec[count].size);
|
||||
|
||||
if (argvec[count].size.var)
|
||||
abort ();
|
||||
|
||||
#ifndef REG_PARM_STACK_SPACE
|
||||
if (argvec[count].partial)
|
||||
argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
|
||||
#endif
|
||||
|
||||
if (argvec[count].reg == 0 || argvec[count].partial != 0
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
|| 1
|
||||
#endif
|
||||
)
|
||||
args_size.constant += argvec[count].size.constant;
|
||||
|
||||
#ifdef ACCUMULATE_OUTGOING_ARGS
|
||||
/* If this arg is actually passed on the stack, it might be
|
||||
clobbering something we already put there (this library call might
|
||||
be inside the evaluation of an argument to a function whose call
|
||||
requires the stack). This will only occur when the library call
|
||||
has sufficient args to run out of argument registers. Abort in
|
||||
this case; if this ever occurs, code must be added to save and
|
||||
restore the arg slot. */
|
||||
|
||||
if (argvec[count].reg == 0 || argvec[count].partial != 0)
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
|
||||
}
|
||||
va_end (p);
|
||||
|
||||
/* If this machine requires an external definition for library
|
||||
functions, write one out. */
|
||||
assemble_external_libcall (fun);
|
||||
|
||||
original_args_size = args_size;
|
||||
#ifdef STACK_BOUNDARY
|
||||
args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
|
||||
/ STACK_BYTES) * STACK_BYTES);
|
||||
#endif
|
||||
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
args_size.constant = MAX (args_size.constant,
|
||||
REG_PARM_STACK_SPACE (NULL_TREE));
|
||||
#ifndef OUTGOING_REG_PARM_STACK_SPACE
|
||||
args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ACCUMULATE_OUTGOING_ARGS
|
||||
if (args_size.constant > current_function_outgoing_args_size)
|
||||
current_function_outgoing_args_size = args_size.constant;
|
||||
args_size.constant = 0;
|
||||
#endif
|
||||
|
||||
#ifndef PUSH_ROUNDING
|
||||
argblock = push_block (GEN_INT (args_size.constant), 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
#ifdef STACK_BOUNDARY
|
||||
/* If we push args individually in reverse order, perform stack alignment
|
||||
before the first push (the last arg). */
|
||||
if (argblock == 0)
|
||||
anti_adjust_stack (GEN_INT (args_size.constant
|
||||
- original_args_size.constant));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
inc = -1;
|
||||
argnum = nargs - 1;
|
||||
#else
|
||||
inc = 1;
|
||||
argnum = 0;
|
||||
#endif
|
||||
|
||||
/* Push the args that need to be pushed. */
|
||||
|
||||
for (count = 0; count < nargs; count++, argnum += inc)
|
||||
{
|
||||
register enum machine_mode mode = argvec[argnum].mode;
|
||||
register rtx val = argvec[argnum].value;
|
||||
rtx reg = argvec[argnum].reg;
|
||||
int partial = argvec[argnum].partial;
|
||||
|
||||
if (! (reg != 0 && partial == 0))
|
||||
emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
|
||||
argblock, GEN_INT (argvec[count].offset.constant));
|
||||
NO_DEFER_POP;
|
||||
}
|
||||
|
||||
#ifndef PUSH_ARGS_REVERSED
|
||||
#ifdef STACK_BOUNDARY
|
||||
/* If we pushed args in forward order, perform stack alignment
|
||||
after pushing the last arg. */
|
||||
if (argblock == 0)
|
||||
anti_adjust_stack (GEN_INT (args_size.constant
|
||||
- original_args_size.constant));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
argnum = nargs - 1;
|
||||
#else
|
||||
argnum = 0;
|
||||
#endif
|
||||
|
||||
/* Now load any reg parms into their regs. */
|
||||
|
||||
for (count = 0; count < nargs; count++, argnum += inc)
|
||||
{
|
||||
register enum machine_mode mode = argvec[argnum].mode;
|
||||
register rtx val = argvec[argnum].value;
|
||||
rtx reg = argvec[argnum].reg;
|
||||
int partial = argvec[argnum].partial;
|
||||
|
||||
if (reg != 0 && partial == 0)
|
||||
emit_move_insn (reg, val);
|
||||
NO_DEFER_POP;
|
||||
}
|
||||
|
||||
/* For version 1.37, try deleting this entirely. */
|
||||
if (! no_queue)
|
||||
emit_queue ();
|
||||
|
||||
/* Any regs containing parms remain in use through the call. */
|
||||
start_sequence ();
|
||||
for (count = 0; count < nargs; count++)
|
||||
if (argvec[count].reg != 0)
|
||||
emit_insn (gen_rtx (USE, VOIDmode, argvec[count].reg));
|
||||
|
||||
use_insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
fun = prepare_call_address (fun, NULL_TREE, &use_insns);
|
||||
|
||||
/* Don't allow popping to be deferred, since then
|
||||
cse'ing of library calls could delete a call and leave the pop. */
|
||||
NO_DEFER_POP;
|
||||
|
||||
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
|
||||
will set inhibit_defer_pop to that value. */
|
||||
|
||||
emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
|
||||
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
|
||||
outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
|
||||
old_inhibit_defer_pop + 1, use_insns, no_queue);
|
||||
|
||||
/* Now restore inhibit_defer_pop to its actual original value. */
|
||||
OK_DEFER_POP;
|
||||
}
|
||||
|
||||
/* Like emit_library_call except that an extra argument, VALUE,
|
||||
comes second and says where to store the result.
|
||||
(If VALUE is zero, the result comes in the function value register.) */
|
||||
|
||||
void
|
||||
emit_library_call_value (va_alist)
|
||||
va_dcl
|
||||
{
|
||||
va_list p;
|
||||
/* Total size in bytes of all the stack-parms scanned so far. */
|
||||
struct args_size args_size;
|
||||
/* Size of arguments before any adjustments (such as rounding). */
|
||||
struct args_size original_args_size;
|
||||
register int argnum;
|
||||
enum machine_mode outmode;
|
||||
int nargs;
|
||||
rtx fun;
|
||||
rtx orgfun;
|
||||
int inc;
|
||||
int count;
|
||||
rtx argblock = 0;
|
||||
CUMULATIVE_ARGS args_so_far;
|
||||
struct arg { rtx value; enum machine_mode mode; rtx reg; int partial;
|
||||
struct args_size offset; struct args_size size; };
|
||||
struct arg *argvec;
|
||||
int old_inhibit_defer_pop = inhibit_defer_pop;
|
||||
int no_queue = 0;
|
||||
rtx use_insns;
|
||||
rtx value;
|
||||
rtx mem_value = 0;
|
||||
|
||||
va_start (p);
|
||||
orgfun = fun = va_arg (p, rtx);
|
||||
value = va_arg (p, rtx);
|
||||
no_queue = va_arg (p, int);
|
||||
outmode = va_arg (p, enum machine_mode);
|
||||
nargs = va_arg (p, int);
|
||||
|
||||
/* If this kind of value comes back in memory,
|
||||
decide where in memory it should come back. */
|
||||
if (RETURN_IN_MEMORY (type_for_mode (outmode, 0)))
|
||||
{
|
||||
if (GET_CODE (value) == MEM)
|
||||
mem_value = value;
|
||||
else
|
||||
mem_value = assign_stack_temp (outmode, GET_MODE_SIZE (outmode), 0);
|
||||
}
|
||||
|
||||
/* ??? Unfinished: must pass the memory address as an argument. */
|
||||
|
||||
/* Copy all the libcall-arguments out of the varargs data
|
||||
and into a vector ARGVEC.
|
||||
|
||||
Compute how to pass each argument. We only support a very small subset
|
||||
of the full argument passing conventions to limit complexity here since
|
||||
library functions shouldn't have many args. */
|
||||
|
||||
argvec = (struct arg *) alloca ((nargs + 1) * sizeof (struct arg));
|
||||
|
||||
INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun);
|
||||
|
||||
args_size.constant = 0;
|
||||
args_size.var = 0;
|
||||
|
||||
count = 0;
|
||||
|
||||
/* If there's a structure value address to be passed,
|
||||
either pass it in the special place, or pass it as an extra argument. */
|
||||
if (mem_value)
|
||||
{
|
||||
rtx addr = XEXP (mem_value, 0);
|
||||
|
||||
if (! struct_value_rtx)
|
||||
{
|
||||
nargs++;
|
||||
|
||||
/* Make sure it is a reasonable operand for a move or push insn. */
|
||||
if (GET_CODE (addr) != REG && GET_CODE (addr) != MEM
|
||||
&& ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr)))
|
||||
addr = force_operand (addr, NULL_RTX);
|
||||
|
||||
argvec[count].value = addr;
|
||||
argvec[count].mode = outmode;
|
||||
argvec[count].partial = 0;
|
||||
|
||||
argvec[count].reg = FUNCTION_ARG (args_so_far, outmode, NULL_TREE, 1);
|
||||
#ifdef FUNCTION_ARG_PARTIAL_NREGS
|
||||
if (FUNCTION_ARG_PARTIAL_NREGS (args_so_far, outmode, NULL_TREE, 1))
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
locate_and_pad_parm (outmode, NULL_TREE,
|
||||
argvec[count].reg && argvec[count].partial == 0,
|
||||
NULL_TREE, &args_size, &argvec[count].offset,
|
||||
&argvec[count].size);
|
||||
|
||||
|
||||
if (argvec[count].reg == 0 || argvec[count].partial != 0
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
|| 1
|
||||
#endif
|
||||
)
|
||||
args_size.constant += argvec[count].size.constant;
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, outmode, (tree)0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (; count < nargs; count++)
|
||||
{
|
||||
rtx val = va_arg (p, rtx);
|
||||
enum machine_mode mode = va_arg (p, enum machine_mode);
|
||||
|
||||
/* We cannot convert the arg value to the mode the library wants here;
|
||||
must do it earlier where we know the signedness of the arg. */
|
||||
if (mode == BLKmode
|
||||
|| (GET_MODE (val) != mode && GET_MODE (val) != VOIDmode))
|
||||
abort ();
|
||||
|
||||
/* On some machines, there's no way to pass a float to a library fcn.
|
||||
Pass it as a double instead. */
|
||||
#ifdef LIBGCC_NEEDS_DOUBLE
|
||||
if (LIBGCC_NEEDS_DOUBLE && mode == SFmode)
|
||||
val = convert_to_mode (DFmode, val, 0), mode = DFmode;
|
||||
#endif
|
||||
|
||||
/* There's no need to call protect_from_queue, because
|
||||
either emit_move_insn or emit_push_insn will do that. */
|
||||
|
||||
/* Make sure it is a reasonable operand for a move or push insn. */
|
||||
if (GET_CODE (val) != REG && GET_CODE (val) != MEM
|
||||
&& ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
|
||||
val = force_operand (val, NULL_RTX);
|
||||
|
||||
argvec[count].value = val;
|
||||
argvec[count].mode = mode;
|
||||
|
||||
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
|
||||
if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
|
||||
if (argvec[count].reg && GET_CODE (argvec[count].reg) == EXPR_LIST)
|
||||
abort ();
|
||||
#ifdef FUNCTION_ARG_PARTIAL_NREGS
|
||||
argvec[count].partial
|
||||
= FUNCTION_ARG_PARTIAL_NREGS (args_so_far, mode, NULL_TREE, 1);
|
||||
#else
|
||||
argvec[count].partial = 0;
|
||||
#endif
|
||||
|
||||
locate_and_pad_parm (mode, NULL_TREE,
|
||||
argvec[count].reg && argvec[count].partial == 0,
|
||||
NULL_TREE, &args_size, &argvec[count].offset,
|
||||
&argvec[count].size);
|
||||
|
||||
if (argvec[count].size.var)
|
||||
abort ();
|
||||
|
||||
#ifndef REG_PARM_STACK_SPACE
|
||||
if (argvec[count].partial)
|
||||
argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
|
||||
#endif
|
||||
|
||||
if (argvec[count].reg == 0 || argvec[count].partial != 0
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
|| 1
|
||||
#endif
|
||||
)
|
||||
args_size.constant += argvec[count].size.constant;
|
||||
|
||||
#ifdef ACCUMULATE_OUTGOING_ARGS
|
||||
/* If this arg is actually passed on the stack, it might be
|
||||
clobbering something we already put there (this library call might
|
||||
be inside the evaluation of an argument to a function whose call
|
||||
requires the stack). This will only occur when the library call
|
||||
has sufficient args to run out of argument registers. Abort in
|
||||
this case; if this ever occurs, code must be added to save and
|
||||
restore the arg slot. */
|
||||
|
||||
if (argvec[count].reg == 0 || argvec[count].partial != 0)
|
||||
abort ();
|
||||
#endif
|
||||
|
||||
FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree)0, 1);
|
||||
}
|
||||
va_end (p);
|
||||
|
||||
/* If this machine requires an external definition for library
|
||||
functions, write one out. */
|
||||
assemble_external_libcall (fun);
|
||||
|
||||
original_args_size = args_size;
|
||||
#ifdef STACK_BOUNDARY
|
||||
args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
|
||||
/ STACK_BYTES) * STACK_BYTES);
|
||||
#endif
|
||||
|
||||
#ifdef REG_PARM_STACK_SPACE
|
||||
args_size.constant = MAX (args_size.constant,
|
||||
REG_PARM_STACK_SPACE (NULL_TREE));
|
||||
#ifndef OUTGOING_REG_PARM_STACK_SPACE
|
||||
args_size.constant -= REG_PARM_STACK_SPACE (NULL_TREE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef ACCUMULATE_OUTGOING_ARGS
|
||||
if (args_size.constant > current_function_outgoing_args_size)
|
||||
current_function_outgoing_args_size = args_size.constant;
|
||||
args_size.constant = 0;
|
||||
#endif
|
||||
|
||||
#ifndef PUSH_ROUNDING
|
||||
argblock = push_block (GEN_INT (args_size.constant), 0, 0);
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
#ifdef STACK_BOUNDARY
|
||||
/* If we push args individually in reverse order, perform stack alignment
|
||||
before the first push (the last arg). */
|
||||
if (argblock == 0)
|
||||
anti_adjust_stack (GEN_INT (args_size.constant
|
||||
- original_args_size.constant));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
inc = -1;
|
||||
argnum = nargs - 1;
|
||||
#else
|
||||
inc = 1;
|
||||
argnum = 0;
|
||||
#endif
|
||||
|
||||
/* Push the args that need to be pushed. */
|
||||
|
||||
for (count = 0; count < nargs; count++, argnum += inc)
|
||||
{
|
||||
register enum machine_mode mode = argvec[argnum].mode;
|
||||
register rtx val = argvec[argnum].value;
|
||||
rtx reg = argvec[argnum].reg;
|
||||
int partial = argvec[argnum].partial;
|
||||
|
||||
if (! (reg != 0 && partial == 0))
|
||||
emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
|
||||
argblock, GEN_INT (argvec[count].offset.constant));
|
||||
NO_DEFER_POP;
|
||||
}
|
||||
|
||||
#ifndef PUSH_ARGS_REVERSED
|
||||
#ifdef STACK_BOUNDARY
|
||||
/* If we pushed args in forward order, perform stack alignment
|
||||
after pushing the last arg. */
|
||||
if (argblock == 0)
|
||||
anti_adjust_stack (GEN_INT (args_size.constant
|
||||
- original_args_size.constant));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef PUSH_ARGS_REVERSED
|
||||
argnum = nargs - 1;
|
||||
#else
|
||||
argnum = 0;
|
||||
#endif
|
||||
|
||||
/* Now load any reg parms into their regs. */
|
||||
|
||||
if (mem_value != 0 && struct_value_rtx != 0)
|
||||
emit_move_insn (struct_value_rtx, XEXP (mem_value, 0));
|
||||
|
||||
for (count = 0; count < nargs; count++, argnum += inc)
|
||||
{
|
||||
register enum machine_mode mode = argvec[argnum].mode;
|
||||
register rtx val = argvec[argnum].value;
|
||||
rtx reg = argvec[argnum].reg;
|
||||
int partial = argvec[argnum].partial;
|
||||
|
||||
if (reg != 0 && partial == 0)
|
||||
emit_move_insn (reg, val);
|
||||
NO_DEFER_POP;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* For version 1.37, try deleting this entirely. */
|
||||
if (! no_queue)
|
||||
emit_queue ();
|
||||
#endif
|
||||
|
||||
/* Any regs containing parms remain in use through the call. */
|
||||
start_sequence ();
|
||||
for (count = 0; count < nargs; count++)
|
||||
if (argvec[count].reg != 0)
|
||||
emit_insn (gen_rtx (USE, VOIDmode, argvec[count].reg));
|
||||
|
||||
use_insns = get_insns ();
|
||||
end_sequence ();
|
||||
|
||||
fun = prepare_call_address (fun, NULL_TREE, &use_insns);
|
||||
|
||||
/* Don't allow popping to be deferred, since then
|
||||
cse'ing of library calls could delete a call and leave the pop. */
|
||||
NO_DEFER_POP;
|
||||
|
||||
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
|
||||
will set inhibit_defer_pop to that value. */
|
||||
|
||||
emit_call_1 (fun, get_identifier (XSTR (orgfun, 0)), args_size.constant, 0,
|
||||
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
|
||||
outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
|
||||
old_inhibit_defer_pop + 1, use_insns, no_queue);
|
||||
|
||||
/* Now restore inhibit_defer_pop to its actual original value. */
|
||||
OK_DEFER_POP;
|
||||
|
||||
/* Copy the value to the right place. */
|
||||
if (outmode != VOIDmode)
|
||||
{
|
||||
if (mem_value)
|
||||
{
|
||||
if (value == 0)
|
||||
value = hard_libcall_value (outmode);
|
||||
if (value != mem_value)
|
||||
emit_move_insn (value, mem_value);
|
||||
}
|
||||
else if (value != 0)
|
||||
emit_move_insn (value, hard_libcall_value (outmode));
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Return an rtx which represents a suitable home on the stack
|
||||
given TYPE, the type of the argument looking for a home.
|
||||
|
|
Loading…
Reference in New Issue