* calls.c: re-install Mar 16 emit_library_call merge.

From-SVN: r32685
This commit is contained in:
Jan Hubicka 2000-03-22 11:51:10 +01:00 committed by Jan Hubicka
parent 7e9d4b22c9
commit de76b46753
2 changed files with 114 additions and 569 deletions

View File

@ -1,3 +1,7 @@
Wed Mar 22 11:44:50 MET 2000 Jan Hubicka <jh@suse.cz>
* calls.c: re-install Mar 16 emit_library_call merge.
2000-03-21 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.c (mem_min_alignment): If not optimizing,

View File

@ -172,6 +172,9 @@ static rtx rtx_for_function_call PARAMS ((tree, tree));
static void load_register_parameters PARAMS ((struct arg_data *,
int, rtx *));
static int libfunc_nothrow PARAMS ((rtx));
static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx, int,
enum machine_mode,
int, va_list));
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *));
@ -3026,559 +3029,20 @@ libfunc_nothrow (fun)
return 1;
}
/* 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 VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
int nargs, ...))
{
#ifndef ANSI_PROTOTYPES
rtx orgfun;
int no_queue;
enum machine_mode outmode;
int nargs;
#endif
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;
rtx fun;
int inc;
int count;
struct args_size alignment_pad;
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; rtx save_area; };
struct arg *argvec;
int old_inhibit_defer_pop = inhibit_defer_pop;
rtx call_fusage = 0;
int reg_parm_stack_space = 0;
int nothrow;
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
int low_to_save = -1, high_to_save = 0;
rtx save_area = 0; /* Place that it is saved */
#endif
#ifdef ACCUMULATE_OUTGOING_ARGS
int initial_highest_arg_in_use = highest_outgoing_arg_in_use;
char *initial_stack_usage_map = stack_usage_map;
int needed;
#endif
#ifdef REG_PARM_STACK_SPACE
/* Size of the stack reserved for parameter registers. */
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
#else
reg_parm_stack_space = REG_PARM_STACK_SPACE ((tree) 0);
#endif
#endif
VA_START (p, nargs);
#ifndef ANSI_PROTOTYPES
orgfun = va_arg (p, rtx);
no_queue = va_arg (p, int);
outmode = va_arg (p, enum machine_mode);
nargs = va_arg (p, int);
#endif
fun = orgfun;
nothrow = libfunc_nothrow (fun);
/* 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));
bzero ((char *) argvec, nargs * sizeof (struct arg));
INIT_CUMULATIVE_ARGS (args_so_far, NULL_TREE, fun, 0);
args_size.constant = 0;
args_size.var = 0;
push_temp_slots ();
#ifdef PREFERRED_STACK_BOUNDARY
/* Ensure current function's preferred stack boundary is at least
what we need. */
if (cfun->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
cfun->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
#endif
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_modes (DFmode, SFmode, 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);
#ifdef FUNCTION_ARG_PASS_BY_REFERENCE
if (FUNCTION_ARG_PASS_BY_REFERENCE (args_so_far, mode, NULL_TREE, 1))
{
/* We do not support FUNCTION_ARG_CALLEE_COPIES here since it can
be viewed as just an efficiency improvement. */
rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
emit_move_insn (slot, val);
val = force_operand (XEXP (slot, 0), NULL_RTX);
mode = Pmode;
}
#endif
argvec[count].value = val;
argvec[count].mode = mode;
argvec[count].reg = FUNCTION_ARG (args_so_far, mode, NULL_TREE, 1);
#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, &alignment_pad);
if (argvec[count].size.var)
abort ();
if (reg_parm_stack_space == 0 && argvec[count].partial)
argvec[count].size.constant -= argvec[count].partial * UNITS_PER_WORD;
if (argvec[count].reg == 0 || argvec[count].partial != 0
|| reg_parm_stack_space > 0)
args_size.constant += argvec[count].size.constant;
FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
}
va_end (p);
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
args_size.var);
#endif
/* If this machine requires an external definition for library
functions, write one out. */
assemble_external_libcall (fun);
original_args_size = args_size;
#ifdef PREFERRED_STACK_BOUNDARY
args_size.constant = (((args_size.constant + (STACK_BYTES - 1))
/ STACK_BYTES) * STACK_BYTES);
#endif
args_size.constant = MAX (args_size.constant,
reg_parm_stack_space);
#ifndef OUTGOING_REG_PARM_STACK_SPACE
args_size.constant -= reg_parm_stack_space;
#endif
if (args_size.constant > current_function_outgoing_args_size)
current_function_outgoing_args_size = args_size.constant;
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Since the stack pointer will never be pushed, it is possible for
the evaluation of a parm to clobber something we have already
written to the stack. Since most function calls on RISC machines
do not use the stack, this is uncommon, but must work correctly.
Therefore, we save any area of the stack that was already written
and that we are using. Here we set up to do this by making a new
stack usage map from the old one.
Another approach might be to try to reorder the argument
evaluations to avoid this conflicting stack usage. */
needed = args_size.constant;
#ifndef OUTGOING_REG_PARM_STACK_SPACE
/* Since we will be writing into the entire argument area, the
map must be allocated for its entire size, not just the part that
is the responsibility of the caller. */
needed += reg_parm_stack_space;
#endif
#ifdef ARGS_GROW_DOWNWARD
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed + 1);
#else
highest_outgoing_arg_in_use = MAX (initial_highest_arg_in_use,
needed);
#endif
stack_usage_map = (char *) alloca (highest_outgoing_arg_in_use);
if (initial_highest_arg_in_use)
bcopy (initial_stack_usage_map, stack_usage_map,
initial_highest_arg_in_use);
if (initial_highest_arg_in_use != highest_outgoing_arg_in_use)
bzero (&stack_usage_map[initial_highest_arg_in_use],
highest_outgoing_arg_in_use - initial_highest_arg_in_use);
needed = 0;
/* The address of the outgoing argument list must not be copied to a
register here, because argblock would be left pointing to the
wrong place after the call to allocate_dynamic_stack_space below.
*/
argblock = virtual_outgoing_args_rtx;
#else /* not ACCUMULATE_OUTGOING_ARGS */
#ifndef PUSH_ROUNDING
argblock = push_block (GEN_INT (args_size.constant), 0, 0);
#endif
#endif
#ifdef PUSH_ARGS_REVERSED
#ifdef PREFERRED_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
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
/* The argument list is the property of the called routine and it
may clobber it. If the fixed area has been used for previous
parameters, we must save and restore it.
Here we compute the boundary of the that needs to be saved, if any. */
#ifdef ARGS_GROW_DOWNWARD
for (count = 0; count < reg_parm_stack_space + 1; count++)
#else
for (count = 0; count < reg_parm_stack_space; count++)
#endif
{
if (count >= highest_outgoing_arg_in_use
|| stack_usage_map[count] == 0)
continue;
if (low_to_save == -1)
low_to_save = count;
high_to_save = count;
}
if (low_to_save >= 0)
{
int num_to_save = high_to_save - low_to_save + 1;
enum machine_mode save_mode
= mode_for_size (num_to_save * BITS_PER_UNIT, MODE_INT, 1);
rtx stack_area;
/* If we don't have the required alignment, must do this in BLKmode. */
if ((low_to_save & (MIN (GET_MODE_SIZE (save_mode),
BIGGEST_ALIGNMENT / UNITS_PER_WORD) - 1)))
save_mode = BLKmode;
#ifdef ARGS_GROW_DOWNWARD
stack_area = gen_rtx_MEM (save_mode,
memory_address (save_mode,
plus_constant (argblock,
- high_to_save)));
#else
stack_area = gen_rtx_MEM (save_mode,
memory_address (save_mode,
plus_constant (argblock,
low_to_save)));
#endif
if (save_mode == BLKmode)
{
save_area = assign_stack_temp (BLKmode, num_to_save, 0);
emit_block_move (validize_mem (save_area), stack_area,
GEN_INT (num_to_save),
PARM_BOUNDARY / BITS_PER_UNIT);
}
else
{
save_area = gen_reg_rtx (save_mode);
emit_move_insn (save_area, stack_area);
}
}
#endif
/* Push the args that need to be pushed. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
are 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;
#ifdef ACCUMULATE_OUTGOING_ARGS
int lower_bound, upper_bound, i;
#endif
if (! (reg != 0 && partial == 0))
{
#ifdef ACCUMULATE_OUTGOING_ARGS
/* If this is being stored into a pre-allocated, fixed-size, stack
area, save any previous data at that location. */
#ifdef ARGS_GROW_DOWNWARD
/* stack_slot is negative, but we want to index stack_usage_map
with positive values. */
upper_bound = -argvec[argnum].offset.constant + 1;
lower_bound = upper_bound - argvec[argnum].size.constant;
#else
lower_bound = argvec[argnum].offset.constant;
upper_bound = lower_bound + argvec[argnum].size.constant;
#endif
for (i = lower_bound; i < upper_bound; i++)
if (stack_usage_map[i]
/* Don't store things in the fixed argument area at this point;
it has already been saved. */
&& i > reg_parm_stack_space)
break;
if (i != upper_bound)
{
/* We need to make a save area. See what mode we can make it. */
enum machine_mode save_mode
= mode_for_size (argvec[argnum].size.constant * BITS_PER_UNIT,
MODE_INT, 1);
rtx stack_area
= gen_rtx_MEM
(save_mode,
memory_address
(save_mode,
plus_constant (argblock,
argvec[argnum].offset.constant)));
argvec[argnum].save_area = gen_reg_rtx (save_mode);
emit_move_insn (argvec[argnum].save_area, stack_area);
}
#endif
emit_push_insn (val, mode, NULL_TREE, NULL_RTX, 0, partial, reg, 0,
argblock, GEN_INT (argvec[argnum].offset.constant),
reg_parm_stack_space, ARGS_SIZE_RTX (alignment_pad));
#ifdef ACCUMULATE_OUTGOING_ARGS
/* Now mark the segment we just used. */
for (i = lower_bound; i < upper_bound; i++)
stack_usage_map[i] = 1;
#endif
NO_DEFER_POP;
}
}
#ifndef PUSH_ARGS_REVERSED
#ifdef PREFERRED_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
fun = prepare_call_address (fun, NULL_TREE, &call_fusage, 0);
/* Now load any reg parms into their regs. */
/* ARGNUM indexes the ARGVEC array in the order in which the arguments
are to be pushed. */
for (count = 0; count < nargs; count++, argnum += inc)
{
register rtx val = argvec[argnum].value;
rtx reg = argvec[argnum].reg;
int partial = argvec[argnum].partial;
/* Handle calls that pass values in multiple non-contiguous
locations. The PA64 has examples of this for library calls. */
if (reg != 0 && GET_CODE (reg) == PARALLEL)
emit_group_load (reg, val,
GET_MODE_SIZE (GET_MODE (val)),
GET_MODE_ALIGNMENT (GET_MODE (val)));
else 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. */
for (count = 0; count < nargs; count++)
{
rtx reg = argvec[count].reg;
if (reg != 0 && GET_CODE (argvec[count].reg) == PARALLEL)
use_group_regs (&call_fusage, reg);
else if (reg != 0)
use_reg (&call_fusage, reg);
}
/* 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. */
/* The return type is needed to decide how many bytes the function pops.
Signedness plays no role in that, so for simplicity, we pretend it's
always signed. We also assume that the list of arguments passed has
no impact, so we pretend it is unknown. */
emit_call_1 (fun,
get_identifier (XSTR (orgfun, 0)),
build_function_type (outmode == VOIDmode ? void_type_node
: type_for_mode (outmode, 0), NULL_TREE),
original_args_size.constant, 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, call_fusage,
((no_queue ? ECF_IS_CONST : 0)
| (nothrow ? ECF_NOTHROW : 0)));
pop_temp_slots ();
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
#ifdef ACCUMULATE_OUTGOING_ARGS
#ifdef REG_PARM_STACK_SPACE
if (save_area)
{
enum machine_mode save_mode = GET_MODE (save_area);
#ifdef ARGS_GROW_DOWNWARD
rtx stack_area
= gen_rtx_MEM (save_mode,
memory_address (save_mode,
plus_constant (argblock,
- high_to_save)));
#else
rtx stack_area
= gen_rtx_MEM (save_mode,
memory_address (save_mode,
plus_constant (argblock, low_to_save)));
#endif
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),
PARM_BOUNDARY / BITS_PER_UNIT);
}
#endif
/* If we saved any argument areas, restore them. */
for (count = 0; count < nargs; count++)
if (argvec[count].save_area)
{
enum machine_mode save_mode = GET_MODE (argvec[count].save_area);
rtx stack_area
= gen_rtx_MEM (save_mode,
memory_address
(save_mode,
plus_constant (argblock,
argvec[count].offset.constant)));
emit_move_insn (stack_area, argvec[count].save_area);
}
highest_outgoing_arg_in_use = initial_highest_arg_in_use;
stack_usage_map = initial_stack_usage_map;
#endif
}
/* Like emit_library_call except that an extra argument, VALUE,
comes second and says where to store the result.
(If VALUE is zero, this function chooses a convenient way
to return the value.
This function returns an rtx for where the value is to be found.
If VALUE is nonzero, VALUE is returned. */
rtx
emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
enum machine_mode outmode, int nargs, ...))
/* Output a library call to function FUN (a SYMBOL_REF rtx).
The RETVAL parameter specifies whether return value needs to be saved, other
parameters are documented in the emit_library_call function bellow. */
static rtx
emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
int retval;
rtx orgfun;
rtx value;
int no_queue;
enum machine_mode outmode;
int nargs;
va_list p;
{
#ifndef ANSI_PROTOTYPES
rtx orgfun;
rtx value;
int no_queue;
enum machine_mode outmode;
int nargs;
#endif
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). */
@ -3626,16 +3090,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
#endif
#endif
VA_START (p, nargs);
#ifndef ANSI_PROTOTYPES
orgfun = 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);
#endif
is_const = no_queue;
fun = orgfun;
@ -3650,7 +3104,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
/* If this kind of value comes back in memory,
decide where in memory it should come back. */
if (aggregate_value_p (type_for_mode (outmode, 0)))
if (outmode != VOIDmode && aggregate_value_p (type_for_mode (outmode, 0)))
{
#ifdef PCC_STATIC_STRUCT_RETURN
rtx pointer_reg
@ -3763,7 +3217,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
be viewed as just an efficiency improvement. */
rtx slot = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
emit_move_insn (slot, val);
val = XEXP (slot, 0);
val = force_operand (XEXP (slot, 0), NULL_RTX);
mode = Pmode;
}
#endif
@ -3797,7 +3251,6 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
FUNCTION_ARG_ADVANCE (args_so_far, mode, (tree) 0, 1);
}
va_end (p);
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
@ -4096,16 +3549,19 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
/* We pass the old value of inhibit_defer_pop + 1 to emit_call_1, which
will set inhibit_defer_pop to that value. */
/* See the comment in emit_library_call about the function type we build
and pass here. */
/* The return type is needed to decide how many bytes the function pops.
Signedness plays no role in that, so for simplicity, we pretend it's
always signed. We also assume that the list of arguments passed has
no impact, so we pretend it is unknown. */
emit_call_1 (fun,
get_identifier (XSTR (orgfun, 0)),
build_function_type (type_for_mode (outmode, 0), NULL_TREE),
build_function_type (outmode == VOIDmode ? void_type_node
: type_for_mode (outmode, 0), NULL_TREE),
original_args_size.constant, args_size.constant,
struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
mem_value == 0 ? hard_libcall_value (outmode) : NULL_RTX,
mem_value == 0 && outmode != VOIDmode ? hard_libcall_value (outmode) : NULL_RTX,
old_inhibit_defer_pop + 1, call_fusage,
((is_const ? ECF_IS_CONST : 0)
| (nothrow ? ECF_NOTHROW : 0)));
@ -4116,7 +3572,7 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
pop_temp_slots ();
/* Copy the value to the right place. */
if (outmode != VOIDmode)
if (outmode != VOIDmode && retval)
{
if (mem_value)
{
@ -4176,6 +3632,91 @@ emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
stack_usage_map = initial_stack_usage_map;
#endif
return value;
}
/* 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 VPARAMS((rtx orgfun, int no_queue, enum machine_mode outmode,
int nargs, ...))
{
#ifndef ANSI_PROTOTYPES
rtx orgfun;
int no_queue;
enum machine_mode outmode;
int nargs;
#endif
va_list p;
VA_START (p, nargs);
#ifndef ANSI_PROTOTYPES
orgfun = va_arg (p, rtx);
no_queue = va_arg (p, int);
outmode = va_arg (p, enum machine_mode);
nargs = va_arg (p, int);
#endif
emit_library_call_value_1 (0, orgfun, NULL_RTX, no_queue, outmode, nargs, p);
va_end (p);
}
/* Like emit_library_call except that an extra argument, VALUE,
comes second and says where to store the result.
(If VALUE is zero, this function chooses a convenient way
to return the value.
This function returns an rtx for where the value is to be found.
If VALUE is nonzero, VALUE is returned. */
rtx
emit_library_call_value VPARAMS((rtx orgfun, rtx value, int no_queue,
enum machine_mode outmode, int nargs, ...))
{
#ifndef ANSI_PROTOTYPES
rtx orgfun;
rtx value;
int no_queue;
enum machine_mode outmode;
int nargs;
#endif
va_list p;
VA_START (p, nargs);
#ifndef ANSI_PROTOTYPES
orgfun = 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);
#endif
value = emit_library_call_value_1 (1, orgfun, value, no_queue, outmode, nargs, p);
va_end (p);
return value;
}