calls.c (special_function_p): Push alloca test inside the large conditional which excludes functions not at...

* calls.c (special_function_p): Push alloca test inside the large
        conditional which excludes functions not at file scope or not
        extern.

From-SVN: r24524
This commit is contained in:
Jeffrey A Law 1999-01-06 17:57:29 +00:00 committed by Jeff Law
parent bc3ca41b49
commit ca54603f6a
2 changed files with 113 additions and 12 deletions

View File

@ -7,6 +7,10 @@ Wed Jan 6 17:55:19 1999 Robert Lipe <robertlipe@usa.net>
Wed Jan 6 16:08:54 1999 Jeffrey A Law (law@cygnus.com)
* calls.c (special_function_p): Push alloca test inside the large
conditional which excludes functions not at file scope or not
extern.
* calls.c (special_function_p): New function broken out of
expand_call.
(precompute_register_parameters): Likewise.

View File

@ -33,6 +33,10 @@ Boston, MA 02111-1307, USA. */
#define PREFERRED_STACK_BOUNDARY STACK_BOUNDARY
#endif
extern int frame_offset;
extern rtx tail_recursion_label;
extern rtx tail_recursion_reentry;
/* Decide whether a function's arguments should be processed
from first to last or from last to first.
@ -62,6 +66,8 @@ struct arg_data
rtx value;
/* Initially-compute RTL value for argument; only for const functions. */
rtx initial_value;
/* */
rtx sibcall_value;
/* Register to pass this argument in, 0 if passed on stack, or an
PARALLEL if the arg is to be copied into multiple non-contiguous
registers. */
@ -515,17 +521,6 @@ special_function_p (name, fndecl, returns_twice, is_longjmp,
*is_malloc = 0;
*may_be_alloca = 0;
/* 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
= (name && ((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 (name != 0 && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
/* Exclude functions not at the file scope, or not `extern',
since they are not the magic functions we would otherwise
@ -534,6 +529,17 @@ special_function_p (name, fndecl, returns_twice, is_longjmp,
{
char *tname = name;
/* 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"))));
/* Disregard prefix _, __ or __x. */
if (name[0] == '_')
{
@ -834,6 +840,7 @@ expand_call (exp, target, ignore)
tree actparms = TREE_OPERAND (exp, 1);
/* RTX for the function to be called. */
rtx funexp;
rtx tail_recursion_insns = NULL_RTX;
/* Data type of the function. */
tree funtype;
/* Declaration of the function being called,
@ -1916,6 +1923,7 @@ expand_call (exp, target, ignore)
once we have started filling any specific hard regs. */
precompute_register_parameters (num_actuals, args, &reg_parm_seen);
#if defined(ACCUMULATE_OUTGOING_ARGS) && defined(REG_PARM_STACK_SPACE)
/* Save the fixed argument area if it's part of the caller's frame and
@ -2063,6 +2071,92 @@ expand_call (exp, target, ignore)
}
}
/* See if this is a potential tail recursive call. We can not know for
sure until we have expanded the entire function into RTL and can examine
the cfg and other data. But we have to mark it and save some information
now so that we can optimize it later. */
if (optimize
&& TREE_CODE (exp) == CALL_EXPR
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& TREE_OPERAND (TREE_OPERAND (exp, 0), 0) == current_function_decl)
{
tree actuals, formals, a, f;
int i;
actuals = TREE_OPERAND (exp, 1);
formals = DECL_ARGUMENTS (current_function_decl);
/* The caller and callee must have the same number of arguments and
they must be of compatible types and modes. */
for (a = actuals, f = formals, i = 0;
a != NULL_TREE && f != NULL_TREE;
a = TREE_CHAIN (a) , f = TREE_CHAIN (f), i++)
{
if (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (a)))
!= TYPE_MAIN_VARIANT (TREE_TYPE (f)))
break;
if (GET_CODE (DECL_RTL (f)) != REG || DECL_MODE (f) == BLKmode)
break;
if (!args[i].sibcall_value)
args[i].sibcall_value = args[i].value;
}
if (a == NULL_TREE && f == NULL_TREE)
{
/* Create the tail recursion label if it has not been created
already. */
if (tail_recursion_label == 0)
{
tail_recursion_label = gen_label_rtx ();
emit_label_after (tail_recursion_label, tail_recursion_reentry);
}
/* We have a potential tail recursion site.
Start a new sequence for any RTL generated which might be used
to implement tail recursion optimizations later. */
push_to_sequence (0);
/* Find which actual values refer to current values of previous
formals. Copy each of them now, before any formal is changed. */
for (a = actuals, i = 0; a != NULL_TREE; a = TREE_CHAIN (a), i++)
{
int copy = 0, j;
for (f = formals, j = 0; j < i; f = TREE_CHAIN (f), j++)
if (reg_mentioned_p (DECL_RTL (f), args[i].value))
{
copy = 1;
break;
}
if (copy)
args[i].sibcall_value = copy_to_reg (args[i].value);
}
/* Store the values of the actuals into the formals. */
for (f = formals, a = actuals, i = 0; f != NULL_TREE;
f = TREE_CHAIN (f), a = TREE_CHAIN (a), i++)
{
if (GET_MODE (DECL_RTL (f)) == GET_MODE (args[i].sibcall_value))
emit_move_insn (DECL_RTL (f), args[i].sibcall_value);
else
convert_move (DECL_RTL (f), args[i].sibcall_value,
TREE_UNSIGNED (TREE_TYPE (TREE_VALUE (a))));
}
/* Emit any queued operations. */
emit_queue ();
/* Goto the tail recursion label. */
expand_goto_internal (NULL_TREE, tail_recursion_label, get_last_insn);
tail_recursion_insns = get_insns ();
end_sequence ();
emit_insns (tail_recursion_insns);
return;
}
}
/* Perform postincrements before actually calling the function. */
emit_queue ();
@ -3690,7 +3784,10 @@ store_one_arg (arg, argblock, may_be_alloca, variable_size,
arg->stack_slot and it matters when they are not the same.
It isn't totally clear that this is correct in all cases. */
if (partial == 0)
arg->value = arg->stack_slot;
{
arg->sibcall_value = arg->value;
arg->value = arg->stack_slot;
}
/* Once we have pushed something, pops can't safely
be deferred during the rest of the arguments. */