aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeffrey A Law <law@cygnus.com>1999-01-06 17:57:29 +0000
committerJeff Law <law@gcc.gnu.org>1999-01-06 10:57:29 -0700
commitca54603f6a9b94cc240631068bbfd8bb4c8a7a88 (patch)
tree96e64d505348d8523d51431ac76828389cbc48a3
parentbc3ca41b4911ec74cd970904c5a91402bdeeb424 (diff)
downloadgcc-ca54603f6a9b94cc240631068bbfd8bb4c8a7a88.zip
gcc-ca54603f6a9b94cc240631068bbfd8bb4c8a7a88.tar.gz
gcc-ca54603f6a9b94cc240631068bbfd8bb4c8a7a88.tar.bz2
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
-rw-r--r--gcc/ChangeLog4
-rw-r--r--gcc/calls.c121
2 files changed, 113 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 174f647..b7b8c7a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/calls.c b/gcc/calls.c
index 2d2b4f4..95a29f7 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -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. */