calls.c (ECF_MALLOC, [...]): New constants.

* calls.c (ECF_MALLOC, ECF_MAY_BE_ALLOCA, ECF_RETURNS_TWICE,
	 ECF_LONGJMP, ECF_FORK_OR_EXEC):  New constants.
	(ECF_IS_CONST): Rename to ECF_CONST.
	(special_function_p): Make static, change interface.
	(flags_from_decl_or_type, try_to_integrate): Break out from ...
	(expand_call) ... here; convert number of variables to flags.
	(emit_library_call_vlue_1): Likewise.
	(setjmp_call_p): New function.
	(initialize_argument_information): Accepts flags as argument;
	return flags.
	(precompute_arguments): Likewise.
	* tree.h (special_function_p): Remove.
	(setjmp_call_p): Add prototype.

From-SVN: r32904
This commit is contained in:
Jan Hubicka 2000-04-04 17:19:30 +00:00 committed by Jan Hubicka
parent be340b974a
commit f2d33f1321
4 changed files with 283 additions and 225 deletions

View File

@ -1,3 +1,19 @@
Tue Apr 4 19:17:20 MET DST 2000 Jan Hubicka <jh@suse.cz>
* calls.c (ECF_MALLOC, ECF_MAY_BE_ALLOCA, ECF_RETURNS_TWICE,
ECF_LONGJMP, ECF_FORK_OR_EXEC): New constants.
(ECF_IS_CONST): Rename to ECF_CONST.
(special_function_p): Make static, change interface.
(flags_from_decl_or_type, try_to_integrate): Break out from ...
(expand_call) ... here; convert number of variables to flags.
(emit_library_call_vlue_1): Likewise.
(setjmp_call_p): New function.
(initialize_argument_information): Accepts flags as argument;
return flags.
(precompute_arguments): Likewise.
* tree.h (special_function_p): Remove.
(setjmp_call_p): Add prototype.
2000-04-04 Jakub Jelinek <jakub@redhat.com>
* config/sparc/sparc.h (RTX_OK_FOR_OFFSET_P): Leave minor margin

View File

@ -150,9 +150,25 @@ int stack_arg_under_construction;
static int calls_function PARAMS ((tree, int));
static int calls_function_1 PARAMS ((tree, int));
#define ECF_IS_CONST 1
#define ECF_NOTHROW 2
#define ECF_SIBCALL 4
/* Nonzero if this is a call to a `const' function. */
#define ECF_CONST 1
/* Nonzero if this is a call to a `volatile' function. */
#define ECF_NORETURN 2
/* Nonzero if this is a call to malloc or a related function. */
#define ECF_MALLOC 4
/* Nonzero if it is plausible that this is a call to alloca. */
#define ECF_MAY_BE_ALLOCA 8
/* Nonzero if this is a call to a function that won't throw an exception. */
#define ECF_NOTHROW 16
/* Nonzero if this is a call to setjmp or a related function. */
#define ECF_RETURNS_TWICE 32
/* Nonzero if this is a call to `longjmp'. */
#define ECF_LONGJMP 64
/* Nonzero if this is a syscall that makes a new process in the image of
the current one. */
#define ECF_FORK_OR_EXEC 128
#define ECF_SIBCALL 256
static void emit_call_1 PARAMS ((rtx, tree, tree, HOST_WIDE_INT,
HOST_WIDE_INT, HOST_WIDE_INT, rtx,
rtx, int, rtx, int));
@ -178,7 +194,7 @@ static void initialize_argument_information PARAMS ((int,
int, tree, tree,
CUMULATIVE_ARGS *,
int, rtx *, int *,
int *, int *, int));
int *, int *));
static void compute_argument_addresses PARAMS ((struct arg_data *,
rtx, int));
static rtx rtx_for_function_call PARAMS ((tree, tree));
@ -188,6 +204,10 @@ static int libfunc_nothrow PARAMS ((rtx));
static rtx emit_library_call_value_1 PARAMS ((int, rtx, rtx, int,
enum machine_mode,
int, va_list));
static int special_function_p PARAMS ((tree, int));
static int flags_from_decl_or_type PARAMS ((tree));
static rtx try_to_integrate PARAMS ((tree, tree, rtx,
int, tree, rtx));
#ifdef REG_PARM_STACK_SPACE
static rtx save_fixed_argument_area PARAMS ((int, rtx, int *, int *));
@ -401,9 +421,7 @@ prepare_call_address (funexp, fndecl, call_fusage, reg_parm_seen)
We restore `inhibit_defer_pop' to that value.
CALL_FUSAGE is either empty or an EXPR_LIST of USE expressions that
denote registers used by the called function.
IS_CONST is true if this is a `const' call. */
denote registers used by the called function. */
static void
emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
@ -553,7 +571,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
CALL_INSN_FUNCTION_USAGE (call_insn) = call_fusage;
/* If this is a const call, then set the insn's unchanging bit. */
if (ecf_flags & ECF_IS_CONST)
if (ecf_flags & ECF_CONST)
CONST_CALL_P (call_insn) = 1;
/* If this call can't throw, attach a REG_EH_REGION reg note to that
@ -592,7 +610,7 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
if (rounded_stack_size != 0)
{
if (flag_defer_pop && inhibit_defer_pop == 0
&& !(ecf_flags & ECF_IS_CONST))
&& !(ecf_flags & ECF_CONST))
pending_stack_adjust += rounded_stack_size;
else
adjust_stack (rounded_stack_size_rtx);
@ -619,33 +637,20 @@ emit_call_1 (funexp, fndecl, funtype, stack_size, rounded_stack_size,
For example, if the function might return more than one time (setjmp), then
set RETURNS_TWICE to a nonzero value.
Similarly set IS_LONGJMP for if the function is in the longjmp family.
Similarly set LONGJMP for if the function is in the longjmp family.
Set IS_MALLOC for any of the standard memory allocation functions which
Set MALLOC for any of the standard memory allocation functions which
allocate from the heap.
Set MAY_BE_ALLOCA for any memory allocation function that might allocate
space from the stack such as alloca. */
void
special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
is_malloc, may_be_alloca)
static int
special_function_p (fndecl, flags)
tree fndecl;
int *returns_twice;
int *is_longjmp;
int *fork_or_exec;
int *is_malloc;
int *may_be_alloca;
int flags;
{
*returns_twice = 0;
*is_longjmp = 0;
*fork_or_exec = 0;
*may_be_alloca = 0;
/* The function decl may have the `malloc' attribute. */
*is_malloc = fndecl && DECL_IS_MALLOC (fndecl);
if (! *is_malloc
if (! (flags & ECF_MALLOC)
&& fndecl && DECL_NAME (fndecl)
&& IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
/* Exclude functions not at the file scope, or not `extern',
@ -659,13 +664,13 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
/* We assume that alloca will always be called by name. It
makes no sense to pass it as a pointer-to-function to
anything that does not understand its behavior. */
*may_be_alloca
= (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
&& name[0] == 'a'
&& ! strcmp (name, "alloca"))
|| (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
&& name[0] == '_'
&& ! strcmp (name, "__builtin_alloca"))));
if (((IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 6
&& name[0] == 'a'
&& ! strcmp (name, "alloca"))
|| (IDENTIFIER_LENGTH (DECL_NAME (fndecl)) == 16
&& name[0] == '_'
&& ! strcmp (name, "__builtin_alloca"))))
flags |= ECF_MAY_BE_ALLOCA;
/* Disregard prefix _, __ or __x. */
if (name[0] == '_')
@ -680,27 +685,28 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
if (tname[0] == 's')
{
*returns_twice
= ((tname[1] == 'e'
&& (! strcmp (tname, "setjmp")
|| ! strcmp (tname, "setjmp_syscall")))
|| (tname[1] == 'i'
&& ! strcmp (tname, "sigsetjmp"))
|| (tname[1] == 'a'
&& ! strcmp (tname, "savectx")));
if ((tname[1] == 'e'
&& (! strcmp (tname, "setjmp")
|| ! strcmp (tname, "setjmp_syscall")))
|| (tname[1] == 'i'
&& ! strcmp (tname, "sigsetjmp"))
|| (tname[1] == 'a'
&& ! strcmp (tname, "savectx")))
flags |= ECF_RETURNS_TWICE;
if (tname[1] == 'i'
&& ! strcmp (tname, "siglongjmp"))
*is_longjmp = 1;
flags |= ECF_LONGJMP;
}
else if ((tname[0] == 'q' && tname[1] == 's'
&& ! strcmp (tname, "qsetjmp"))
|| (tname[0] == 'v' && tname[1] == 'f'
&& ! strcmp (tname, "vfork")))
*returns_twice = 1;
flags |= ECF_RETURNS_TWICE;
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
*is_longjmp = 1;
flags |= ECF_LONGJMP;
else if ((tname[0] == 'f' && tname[1] == 'o'
&& ! strcmp (tname, "fork"))
@ -714,7 +720,7 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
&& (tname[5] == '\0'
|| ((tname[5] == 'p' || tname[5] == 'e')
&& tname[6] == '\0'))))
*fork_or_exec = 1;
flags |= ECF_FORK_OR_EXEC;
/* Do not add any more malloc-like functions to this list,
instead mark them as malloc functions using the malloc attribute.
@ -727,10 +733,46 @@ special_function_p (fndecl, returns_twice, is_longjmp, fork_or_exec,
&& (! strcmp (tname, "malloc")
|| ! strcmp (tname, "calloc")
|| ! strcmp (tname, "strdup")))
*is_malloc = 1;
flags |= ECF_MALLOC;
}
return flags;
}
/* Return nonzero when tree represent call to longjmp. */
int
setjmp_call_p (fndecl)
tree fndecl;
{
return special_function_p (fndecl, 0) & ECF_RETURNS_TWICE;
}
/* Detect flags (function attributes) from the function type node. */
static int
flags_from_decl_or_type (exp)
tree exp;
{
int flags = 0;
/* ??? We can't set IS_MALLOC for function types? */
if (DECL_P (exp))
{
/* The function exp may have the `malloc' attribute. */
if (DECL_P (exp) && DECL_IS_MALLOC (exp))
flags |= ECF_MALLOC;
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
}
if (TREE_READONLY (exp) && !TREE_THIS_VOLATILE (exp))
flags |= ECF_CONST;
if (TREE_THIS_VOLATILE (exp))
flags |= ECF_NORETURN;
return flags;
}
/* Precompute all register parameters as described by ARGS, storing values
into fields within the ARGS array.
@ -990,14 +1032,14 @@ store_unaligned_arguments_into_pseudos (args, num_actuals)
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
OLD_PENDING_ADJ, MUST_PREALLOCATE and FLAGS 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,
old_pending_adj, must_preallocate,
ecf_flags)
int num_actuals ATTRIBUTE_UNUSED;
struct arg_data *args;
@ -1010,8 +1052,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
rtx *old_stack_level;
int *old_pending_adj;
int *must_preallocate;
int *is_const;
int ecf_flags ATTRIBUTE_UNUSED;
int *ecf_flags;
{
/* 1 if scanning parms front to back, -1 if scanning back to front. */
int inc;
@ -1154,7 +1195,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
MEM_SET_IN_STRUCT_P (copy, AGGREGATE_TYPE_P (type));
store_expr (args[i].tree_value, copy, 0);
*is_const = 0;
*ecf_flags &= ~ECF_CONST;
args[i].tree_value = build1 (ADDR_EXPR,
build_pointer_type (type),
@ -1213,7 +1254,7 @@ initialize_argument_information (num_actuals, args, args_size, n_named_args,
/* 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;
*ecf_flags &= ~ECF_CONST;
/* Compute the stack-size of this argument. */
if (args[i].reg == 0 || args[i].partial != 0
@ -1358,7 +1399,7 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
/* Precompute parameters as needed for a function call.
IS_CONST indicates the target function is a pure function.
FLAGS is mask of ECF_* constants.
MUST_PREALLOCATE indicates that we must preallocate stack space for
any stack arguments.
@ -1371,8 +1412,8 @@ compute_argument_block_size (reg_parm_stack_space, args_size,
ARGS_SIZE contains information about the size of the arg list. */
static void
precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
int is_const;
precompute_arguments (flags, must_preallocate, num_actuals, args, args_size)
int flags;
int must_preallocate;
int num_actuals;
struct arg_data *args;
@ -1394,7 +1435,7 @@ precompute_arguments (is_const, must_preallocate, num_actuals, args, args_size)
which have already been stored into the stack. */
for (i = 0; i < num_actuals; i++)
if (is_const
if ((flags & ECF_CONST)
|| ((args_size->var != 0 || args_size->constant != 0)
&& calls_function (args[i].tree_value, 1))
|| (must_preallocate
@ -1691,6 +1732,122 @@ load_register_parameters (args, num_actuals, call_fusage)
}
}
/* Try to integreate function. See expand_inline_function for documentation
about the parameters. */
static rtx
try_to_integrate (fndecl, actparms, target, ignore, type, structure_value_addr)
tree fndecl;
tree actparms;
rtx target;
int ignore;
tree type;
rtx structure_value_addr;
{
rtx temp;
rtx before_call;
int i;
rtx old_stack_level = 0;
int reg_parm_stack_space;
#ifdef REG_PARM_STACK_SPACE
#ifdef MAYBE_REG_PARM_STACK_SPACE
reg_parm_stack_space = MAYBE_REG_PARM_STACK_SPACE;
#else
reg_parm_stack_space = REG_PARM_STACK_SPACE (fndecl);
#endif
#endif
before_call = get_last_insn ();
temp = expand_inline_function (fndecl, actparms, target,
ignore, type,
structure_value_addr);
/* If inlining succeeded, return. */
if (temp != (rtx) (HOST_WIDE_INT) - 1)
{
if (ACCUMULATE_OUTGOING_ARGS)
{
/* If the outgoing argument list must be preserved, push
the stack before executing the inlined function if it
makes any calls. */
for (i = reg_parm_stack_space - 1; i >= 0; i--)
if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
break;
if (stack_arg_under_construction || i >= 0)
{
rtx first_insn
= before_call ? NEXT_INSN (before_call) : get_insns ();
rtx insn = NULL_RTX, seq;
/* Look for a call in the inline function code.
If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
nonzero then there is a call and it is not necessary
to scan the insns. */
if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
break;
if (insn)
{
/* Reserve enough stack space so that the largest
argument list of any function call in the inline
function does not overlap the argument list being
evaluated. This is usually an overestimate because
allocate_dynamic_stack_space reserves space for an
outgoing argument list in addition to the requested
space, but there is no way to ask for stack space such
that an argument list of a certain length can be
safely constructed.
Add the stack space reserved for register arguments, if
any, in the inline function. What is really needed is the
largest value of reg_parm_stack_space in the inline
function, but that is not available. Using the current
value of reg_parm_stack_space is wrong, but gives
correct results on all supported machines. */
int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
+ reg_parm_stack_space);
start_sequence ();
emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
allocate_dynamic_stack_space (GEN_INT (adjust),
NULL_RTX, BITS_PER_UNIT);
seq = get_insns ();
end_sequence ();
emit_insns_before (seq, first_insn);
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
}
}
}
/* If the result is equivalent to TARGET, return TARGET to simplify
checks in store_expr. They can be equivalent but not equal in the
case of a function that returns BLKmode. */
if (temp != target && rtx_equal_p (temp, target))
return target;
return temp;
}
/* If inlining failed, mark FNDECL as needing to be compiled
separately after all. If function was declared inline,
give a warning. */
if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
&& optimize > 0 && !TREE_ADDRESSABLE (fndecl))
{
warning_with_decl (fndecl, "inlining failed in call to `%s'");
warning ("called from here");
}
mark_addressable (fndecl);
return (rtx) (HOST_WIDE_INT) - 1;
}
/* Generate all the code for a function call
and return an rtx for its value.
Store the value in TARGET (specified as an rtx) if convenient.
@ -1722,7 +1879,6 @@ expand_call (exp, target, ignore)
or 0 if the function is computed (not known by name). */
tree fndecl = 0;
char *name = 0;
rtx before_call;
rtx insn;
int try_tail_call;
int pass;
@ -1781,26 +1937,10 @@ expand_call (exp, target, ignore)
(on machines that lack push insns), or 0 if space not preallocated. */
rtx argblock = 0;
/* Nonzero if it is plausible that this is a call to alloca. */
int may_be_alloca;
/* Nonzero if this is a call to malloc or a related function. */
int is_malloc;
/* Nonzero if this is a call to setjmp or a related function. */
int returns_twice;
/* Nonzero if this is a call to `longjmp'. */
int is_longjmp;
/* Nonzero if this is a syscall that makes a new process in the image of
the current one. */
int fork_or_exec;
/* Mask of ECF_ flags. */
int flags = 0;
/* Nonzero if this is a call to an inline function. */
int is_integrable = 0;
/* Nonzero if this is a call to a `const' function.
Note that only explicitly named functions are handled as `const' here. */
int is_const = 0;
/* Nonzero if this is a call to a `volatile' function. */
int is_volatile = 0;
/* Nonzero if this is a call to a function that won't throw an exception. */
int nothrow = TREE_NOTHROW (exp);
#ifdef REG_PARM_STACK_SPACE
/* Define the boundary of the register parm stack space that needs to be
save, if any. */
@ -1828,6 +1968,10 @@ expand_call (exp, target, ignore)
if (current_function_check_memory_usage)
target = 0;
/* See if this is "nothrow" function call. */
if (TREE_NOTHROW (exp))
flags |= ECF_NOTHROW;
/* See if we can find a DECL-node for the actual function.
As a result, decide whether this is a call to an integrable function. */
@ -1861,24 +2005,15 @@ expand_call (exp, target, ignore)
mark_addressable (fndecl);
}
if (TREE_READONLY (fndecl) && ! TREE_THIS_VOLATILE (fndecl)
&& TYPE_MODE (TREE_TYPE (exp)) != VOIDmode)
is_const = 1;
if (TREE_THIS_VOLATILE (fndecl))
is_volatile = 1;
if (TREE_NOTHROW (fndecl))
nothrow = 1;
flags |= flags_from_decl_or_type (fndecl);
}
}
/* If we don't have specific function to call, see if we have a
constant or `noreturn' function from the type. */
attributes set in the type. */
if (fndecl == 0)
{
is_const = TREE_READONLY (TREE_TYPE (TREE_TYPE (p)));
is_volatile = TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (p)));
flags |= flags_from_decl_or_type (TREE_TYPE (TREE_TYPE (p)));
}
#ifdef REG_PARM_STACK_SPACE
@ -1905,7 +2040,7 @@ expand_call (exp, target, ignore)
if (aggregate_value_p (exp))
{
/* This call returns a big structure. */
is_const = 0;
flags &= ~ECF_CONST;
#ifdef PCC_STATIC_STRUCT_RETURN
{
@ -1956,95 +2091,11 @@ expand_call (exp, target, ignore)
if (is_integrable)
{
rtx temp;
before_call = get_last_insn ();
temp = expand_inline_function (fndecl, actparms, target,
ignore, TREE_TYPE (exp),
structure_value_addr);
/* If inlining succeeded, return. */
if (temp != (rtx) (HOST_WIDE_INT) -1)
{
if (ACCUMULATE_OUTGOING_ARGS)
{
/* If the outgoing argument list must be preserved, push
the stack before executing the inlined function if it
makes any calls. */
for (i = reg_parm_stack_space - 1; i >= 0; i--)
if (i < highest_outgoing_arg_in_use && stack_usage_map[i] != 0)
break;
if (stack_arg_under_construction || i >= 0)
{
rtx first_insn
= before_call ? NEXT_INSN (before_call) : get_insns ();
rtx insn = NULL_RTX, seq;
/* Look for a call in the inline function code.
If DECL_SAVED_INSNS (fndecl)->outgoing_args_size is
nonzero then there is a call and it is not necessary
to scan the insns. */
if (DECL_SAVED_INSNS (fndecl)->outgoing_args_size == 0)
for (insn = first_insn; insn; insn = NEXT_INSN (insn))
if (GET_CODE (insn) == CALL_INSN)
break;
if (insn)
{
/* Reserve enough stack space so that the largest
argument list of any function call in the inline
function does not overlap the argument list being
evaluated. This is usually an overestimate because
allocate_dynamic_stack_space reserves space for an
outgoing argument list in addition to the requested
space, but there is no way to ask for stack space such
that an argument list of a certain length can be
safely constructed.
Add the stack space reserved for register arguments, if
any, in the inline function. What is really needed is the
largest value of reg_parm_stack_space in the inline
function, but that is not available. Using the current
value of reg_parm_stack_space is wrong, but gives
correct results on all supported machines. */
int adjust = (DECL_SAVED_INSNS (fndecl)->outgoing_args_size
+ reg_parm_stack_space);
start_sequence ();
emit_stack_save (SAVE_BLOCK, &old_stack_level, NULL_RTX);
allocate_dynamic_stack_space (GEN_INT (adjust),
NULL_RTX, BITS_PER_UNIT);
seq = get_insns ();
end_sequence ();
emit_insns_before (seq, first_insn);
emit_stack_restore (SAVE_BLOCK, old_stack_level, NULL_RTX);
}
}
}
/* If the result is equivalent to TARGET, return TARGET to simplify
checks in store_expr. They can be equivalent but not equal in the
case of a function that returns BLKmode. */
if (temp != target && rtx_equal_p (temp, target))
return target;
return temp;
}
/* If inlining failed, mark FNDECL as needing to be compiled
separately after all. If function was declared inline,
give a warning. */
if (DECL_INLINE (fndecl) && warn_inline && !flag_no_inline
&& optimize > 0 && ! TREE_ADDRESSABLE (fndecl))
{
warning_with_decl (fndecl, "inlining failed in call to `%s'");
warning ("called from here");
}
mark_addressable (fndecl);
rtx temp = try_to_integrate (fndecl, actparms, target,
ignore, TREE_TYPE (exp),
structure_value_addr);
if (temp != (rtx) (HOST_WIDE_INT) - 1)
return temp;
}
currently_expanding_call++;
@ -2162,10 +2213,9 @@ expand_call (exp, target, ignore)
/* See if this is a call to a function that can return more than once
or a call to longjmp or malloc. */
special_function_p (fndecl, &returns_twice, &is_longjmp, &fork_or_exec,
&is_malloc, &may_be_alloca);
flags |= special_function_p (fndecl, flags);
if (may_be_alloca)
if (flags & ECF_MAY_BE_ALLOCA)
current_function_calls_alloca = 1;
/* Operand 0 is a pointer-to-function; get the type of the function. */
@ -2225,9 +2275,13 @@ expand_call (exp, target, ignore)
save_pending_stack_adjust = pending_stack_adjust;
save_stack_pointer_delta = stack_pointer_delta;
}
if (pass)
flags &= ~ECF_SIBCALL;
else
flags |= ECF_SIBCALL;
/* Other state variables that we must reinitialize each time
through the loop (that are not initialized by the loop itself. */
through the loop (that are not initialized by the loop itself). */
argblock = 0;
call_fusage = 0;
@ -2239,7 +2293,7 @@ expand_call (exp, target, ignore)
/* When calling a const function, we must pop the stack args right away,
so that the pop is deleted or moved with the call. */
if (is_const)
if (flags & ECF_CONST)
NO_DEFER_POP;
/* Don't let pending stack adjusts add up to too much.
@ -2247,11 +2301,11 @@ expand_call (exp, target, ignore)
this might be a call to alloca or if we are expanding a sibling
call sequence. */
if (pending_stack_adjust >= 32
|| (pending_stack_adjust > 0 && may_be_alloca)
|| (pending_stack_adjust > 0 && (flags & ECF_MAY_BE_ALLOCA))
|| pass == 0)
do_pending_stack_adjust ();
if (profile_arc_flag && fork_or_exec)
if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC))
{
/* A fork duplicates the profile information, and an exec discards
it. We can't rely on fork/exec to be paired. So write out the
@ -2344,8 +2398,7 @@ expand_call (exp, target, ignore)
n_named_args, actparms, fndecl,
&args_so_far, reg_parm_stack_space,
&old_stack_level, &old_pending_adj,
&must_preallocate, &is_const,
(pass == 0) ? ECF_SIBCALL : 0);
&must_preallocate, &flags);
#ifdef FINAL_REG_PARM_STACK_SPACE
reg_parm_stack_space = FINAL_REG_PARM_STACK_SPACE (args_size.constant,
@ -2361,7 +2414,7 @@ expand_call (exp, target, ignore)
Also do not make a sibling call. */
is_const = 0;
flags &= ~ECF_CONST;
must_preallocate = 1;
sibcall_failure = 1;
}
@ -2410,12 +2463,12 @@ expand_call (exp, target, ignore)
structure_value_addr = copy_to_reg (structure_value_addr);
/* Precompute any arguments as needed. */
precompute_arguments (is_const, must_preallocate, num_actuals,
precompute_arguments (flags, must_preallocate, num_actuals,
args, &args_size);
/* Now we are about to start emitting insns that can be deleted
if a libcall is deleted. */
if (is_const || is_malloc)
if (flags & (ECF_CONST | ECF_MALLOC))
start_sequence ();
old_stack_allocated = stack_pointer_delta - pending_stack_adjust;
@ -2598,7 +2651,7 @@ expand_call (exp, target, ignore)
{
/* When the stack adjustment is pending, we get better code
by combining the adjustments. */
if (pending_stack_adjust && ! is_const
if (pending_stack_adjust && ! (flags & ECF_CONST)
&& ! inhibit_defer_pop)
{
int adjust;
@ -2661,7 +2714,7 @@ expand_call (exp, target, ignore)
for (i = 0; i < num_actuals; i++)
if (args[i].reg == 0 || args[i].pass_on_stack)
store_one_arg (&args[i], argblock, may_be_alloca,
store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
args_size.var != 0, reg_parm_stack_space);
/* If we have a parm that is passed in registers but not in memory
@ -2676,7 +2729,7 @@ expand_call (exp, target, ignore)
if (reg_parm_seen)
for (i = 0; i < num_actuals; i++)
if (args[i].partial != 0 && ! args[i].pass_on_stack)
store_one_arg (&args[i], argblock, may_be_alloca,
store_one_arg (&args[i], argblock, flags & ECF_MAY_BE_ALLOCA,
args_size.var != 0, reg_parm_stack_space);
#ifdef PREFERRED_STACK_BOUNDARY
@ -2749,9 +2802,7 @@ expand_call (exp, target, ignore)
emit_call_1 (funexp, fndecl, funtype, unadjusted_args_size,
args_size.constant, struct_value_size,
next_arg_reg, valreg, old_inhibit_defer_pop, call_fusage,
((is_const ? ECF_IS_CONST : 0)
| (nothrow ? ECF_NOTHROW : 0)
| (pass == 0 ? ECF_SIBCALL : 0)));
flags);
/* Verify that we've deallocated all the stack we used. */
if (pass
@ -2762,7 +2813,7 @@ expand_call (exp, target, ignore)
Test valreg so we don't crash; may safely ignore `const'
if return type is void. Disable for PARALLEL return values, because
we have no way to move such values into a pseudo register. */
if (is_const && valreg != 0 && GET_CODE (valreg) != PARALLEL)
if ((flags & ECF_CONST) && valreg != 0 && GET_CODE (valreg) != PARALLEL)
{
rtx note = 0;
rtx temp = gen_reg_rtx (GET_MODE (valreg));
@ -2789,7 +2840,7 @@ expand_call (exp, target, ignore)
valreg = temp;
}
else if (is_const)
else if (flags & ECF_CONST)
{
/* Otherwise, just write out the sequence without a note. */
rtx insns = get_insns ();
@ -2797,7 +2848,7 @@ expand_call (exp, target, ignore)
end_sequence ();
emit_insns (insns);
}
else if (is_malloc)
else if (flags & ECF_MALLOC)
{
rtx temp = gen_reg_rtx (GET_MODE (valreg));
rtx last, insns;
@ -2825,7 +2876,7 @@ expand_call (exp, target, ignore)
if nonvolatile values are live. For functions that cannot return,
inform flow that control does not fall through. */
if (returns_twice || is_volatile || is_longjmp || pass == 0)
if ((flags & (ECF_RETURNS_TWICE | ECF_NORETURN | ECF_LONGJMP)) || pass == 0)
{
/* The barrier or NOTE_INSN_SETJMP note must be emitted
immediately after the CALL_INSN. Some ports emit more
@ -2840,7 +2891,7 @@ expand_call (exp, target, ignore)
abort ();
}
if (returns_twice)
if (flags & ECF_RETURNS_TWICE)
{
emit_note_after (NOTE_INSN_SETJMP, last);
current_function_calls_setjmp = 1;
@ -2850,7 +2901,7 @@ expand_call (exp, target, ignore)
emit_barrier_after (last);
}
if (is_longjmp)
if (flags & ECF_LONGJMP)
current_function_calls_longjmp = 1, sibcall_failure = 1;
/* If this function is returning into a memory location marked as
@ -3008,7 +3059,7 @@ expand_call (exp, target, ignore)
Check for the handler slots since we might not have a save area
for non-local gotos. */
if (may_be_alloca && nonlocal_goto_handler_slots != 0)
if ((flags & ECF_MAY_BE_ALLOCA) && nonlocal_goto_handler_slots != 0)
emit_stack_save (SAVE_NONLOCAL, &nonlocal_goto_stack_level, NULL_RTX);
pop_temp_slots ();
@ -3144,9 +3195,8 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
rtx mem_value = 0;
int pcc_struct_value = 0;
int struct_value_size = 0;
int is_const;
int flags = 0;
int reg_parm_stack_space = 0;
int nothrow;
int needed;
#ifdef REG_PARM_STACK_SPACE
@ -3168,10 +3218,12 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
#endif
#endif
is_const = no_queue;
if (no_queue)
flags |= ECF_CONST;
fun = orgfun;
nothrow = libfunc_nothrow (fun);
if (libfunc_nothrow (fun))
flags |= ECF_NOTHROW;
#ifdef PREFERRED_STACK_BOUNDARY
/* Ensure current function's preferred stack boundary is at least
@ -3201,7 +3253,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
#endif
/* This call returns a big structure. */
is_const = 0;
flags &= ~ECF_CONST;
}
/* ??? Unfinished: must pass the memory address as an argument. */
@ -3645,9 +3697,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
struct_value_size,
FUNCTION_ARG (args_so_far, VOIDmode, void_type_node, 1),
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)));
old_inhibit_defer_pop + 1, call_fusage, flags);
/* Now restore inhibit_defer_pop to its actual original value. */
OK_DEFER_POP;
@ -3729,7 +3779,7 @@ emit_library_call_value_1 (retval, orgfun, value, no_queue, outmode, nargs, p)
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.
to the flag ECF_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,

View File

@ -748,20 +748,11 @@ calls_setjmp_r (tp, walk_subtrees, data)
int *walk_subtrees ATTRIBUTE_UNUSED;
void *data ATTRIBUTE_UNUSED;
{
int setjmp_p;
int longjmp_p;
int fork_or_exec_p;
int malloc_p;
int alloca_p;
/* We're only interested in FUNCTION_DECLS. */
if (TREE_CODE (*tp) != FUNCTION_DECL)
return NULL_TREE;
special_function_p (*tp, &setjmp_p, &longjmp_p, &fork_or_exec_p, &malloc_p,
&alloca_p);
return setjmp_p ? *tp : NULL_TREE;
return setjmp_call_p (*tp);
}
/* Returns non-zero if FN calls `setjmp' or some other function that

View File

@ -2551,8 +2551,9 @@ extern struct rtx_def *emit_line_note PARAMS ((const char *, int));
extern struct rtx_def *emit_line_note_force PARAMS ((const char *, int));
/* In calls.c */
extern void special_function_p PARAMS ((tree, int *, int *,
int *, int *, int *));
/* Flags used by special_function_p. */
extern int setjmp_call_p PARAMS ((tree));
/* In c-typeck.c */
extern int mark_addressable PARAMS ((tree));