rtx before_call;
#endif
rtx insn;
- int safe_for_reeval;
+ int try_tail_call;
int pass;
/* Register in which non-BLKmode value will be returned,
currently_expanding_call++;
- /* If we're considering tail recursion optimizations, verify that the
- arguments are safe for re-evaluation. If we can unsave them, wrap
- each argument in an UNSAVE_EXPR. */
+ /* Tail calls can make things harder to debug, and we're traditionally
+ pushed these optimizations into -O2. Don't try if we're already
+ expanding a call, as that means we're an argument. Similarly, if
+ there's pending loops or cleanups we know there's code to follow
+ the call. */
- safe_for_reeval = 0;
+ try_tail_call = 0;
if (optimize >= 2
&& currently_expanding_call == 1
&& stmt_loop_nest_empty ()
&& ! any_pending_cleanups (1))
{
- /* Verify that each argument is safe for re-evaluation. */
+ tree new_actparms = NULL_TREE;
+
+ /* Ok, we're going to give the tail call the old college try.
+ This means we're going to evaluate the function arguments
+ up to three times. There are two degrees of badness we can
+ encounter, those that can be unsaved and those that can't.
+ (See unsafe_for_reeval commentary for details.)
+
+ Generate a new argument list. Pass safe arguments through
+ unchanged. For the easy badness wrap them in UNSAVE_EXPRs.
+ For hard badness, evaluate them now and put their resulting
+ rtx in a temporary VAR_DECL. */
+
for (p = actparms; p; p = TREE_CHAIN (p))
- if (! safe_for_unsave (TREE_VALUE (p)))
- break;
+ switch (unsafe_for_reeval (TREE_VALUE (p)))
+ {
+ case 0: /* Safe. */
+ new_actparms = tree_cons (TREE_PURPOSE (p), TREE_VALUE (p),
+ new_actparms);
+ break;
- if (p == NULL_TREE)
- {
- tree new_actparms = NULL_TREE, q;
+ case 1: /* Mildly unsafe. */
+ new_actparms = tree_cons (TREE_PURPOSE (p),
+ unsave_expr (TREE_VALUE (p)),
+ new_actparms);
+ break;
- for (p = actparms; p ; p = TREE_CHAIN (p))
+ case 2: /* Wildly unsafe. */
{
- tree np = build_tree_list (TREE_PURPOSE (p),
- unsave_expr (TREE_VALUE (p)));
- if (new_actparms)
- TREE_CHAIN (q) = np;
- else
- new_actparms = np;
- q = np;
+ tree var = build_decl (VAR_DECL, NULL_TREE,
+ TREE_TYPE (TREE_VALUE (p)));
+ DECL_RTL (var) = expand_expr (TREE_VALUE (p), NULL_RTX,
+ VOIDmode, EXPAND_NORMAL);
+ new_actparms = tree_cons (TREE_PURPOSE (p), var, new_actparms);
}
+ break;
- actparms = new_actparms;
- safe_for_reeval = 1;
- }
+ default:
+ abort ();
+ }
+
+ /* We built the new argument chain backwards. */
+ actparms = nreverse (new_actparms);
+
+ /* Expanding one of those dangerous arguments could have added
+ cleanups, but otherwise give it a whirl. */
+ try_tail_call = ! any_pending_cleanups (1);
}
/* Generate a tail recursion sequence when calling ourselves. */
- if (safe_for_reeval
+ if (try_tail_call
&& TREE_CODE (TREE_OPERAND (exp, 0)) == ADDR_EXPR
&& TREE_OPERAND (TREE_OPERAND (exp, 0), 0) == current_function_decl)
{
if (pass == 0)
{
/* Various reasons we can not use a sibling call. */
- if (! safe_for_reeval
+ if (! try_tail_call
#ifdef HAVE_sibcall_epilogue
|| ! HAVE_sibcall_epilogue
#else
/* If the register holding the address is a callee saved
register, then we lose. We have no way to prevent that,
so we only allow calls to named functions. */
+ /* ??? This could be done by having the insn constraints
+ use a register class that is all call-clobbered. Any
+ reload insns generated to fix things up would appear
+ before the sibcall_epilogue. */
|| fndecl == NULL_TREE
|| ! FUNCTION_OK_FOR_SIBCALL (fndecl))
continue;
/* If there are cleanups to be called, don't use a hard reg as target.
We need to double check this and see if it matters anymore. */
- if (any_pending_cleanups (1)
- && target && REG_P (target)
- && REGNO (target) < FIRST_PSEUDO_REGISTER)
- target = 0, sibcall_failure = 1;
+ if (any_pending_cleanups (1))
+ {
+ if (target && REG_P (target)
+ && REGNO (target) < FIRST_PSEUDO_REGISTER)
+ target = 0;
+ sibcall_failure = 1;
+ }
if (TYPE_MODE (TREE_TYPE (exp)) == VOIDmode
|| ignore)
void (*lang_unsave) PARAMS ((tree *));
void (*lang_unsave_expr_now) PARAMS ((tree));
-/* If non-null, a language specific version of safe_for_unsave. */
-int (*lang_safe_for_unsave) PARAMS ((tree));
-
/* The string used as a placeholder instead of a source file name for
built-in tree nodes. The variable, which is dynamically allocated,
should be used; the macro is only used to initialize it. */
return expr;
}
-/* Return nonzero if it is safe to unsave EXPR, else return zero.
- It is not safe to unsave EXPR if it contains any embedded RTL_EXPRs. */
+/* Return 0 if it is safe to evaluate EXPR multiple times,
+ return 1 if it is safe if EXPR is unsaved afterward, or
+ return 2 if it is completely unsafe.
+
+ This assumes that CALL_EXPRs and TARGET_EXPRs are never replicated in
+ an expression tree, so that it safe to unsave them and the surrounding
+ context will be correct.
+
+ SAVE_EXPRs basically *only* appear replicated in an expression tree,
+ occasionally across the whole of a function. It is therefore only
+ safe to unsave a SAVE_EXPR if you know that all occurrences appear
+ below the UNSAVE_EXPR.
+
+ RTL_EXPRs consume their rtl during evaluation. It is therefore
+ never possible to unsave them. */
int
-safe_for_unsave (expr)
+unsafe_for_reeval (expr)
tree expr;
{
enum tree_code code;
- register int i;
+ register int i, tmp, unsafeness;
int first_rtl;
if (expr == NULL_TREE)
code = TREE_CODE (expr);
first_rtl = first_rtl_op (code);
+ unsafeness = 0;
+
switch (code)
{
+ case SAVE_EXPR:
case RTL_EXPR:
- return 0;
+ return 2;
case CALL_EXPR:
if (TREE_OPERAND (expr, 1)
tree exp = TREE_OPERAND (expr, 1);
while (exp)
{
- if (! safe_for_unsave (TREE_VALUE (exp)))
- return 0;
+ tmp = unsafe_for_reeval (TREE_VALUE (exp));
+ if (tmp > 1)
+ return tmp;
exp = TREE_CHAIN (exp);
}
}
+ return 1;
+
+ case TARGET_EXPR:
+ unsafeness = 1;
break;
default:
- if (lang_safe_for_unsave)
- switch ((*lang_safe_for_unsave) (expr))
- {
- case -1:
- break;
- case 0:
- return 0;
- case 1:
- return 1;
- default:
- abort ();
- }
+ /* ??? Add a lang hook if it becomes necessary. */
break;
}
case 'x': /* something random, like an identifier or an ERROR_MARK. */
case 'd': /* A decl node */
case 'b': /* A block node */
- return 1;
+ return 0;
case 'e': /* an expression */
case 'r': /* a reference */
case '2': /* a binary arithmetic expression */
case '1': /* a unary arithmetic expression */
for (i = first_rtl - 1; i >= 0; i--)
- if (! safe_for_unsave (TREE_OPERAND (expr, i)))
- return 0;
- return 1;
+ {
+ tmp = unsafe_for_reeval (TREE_OPERAND (expr, i));
+ if (tmp > unsafeness)
+ unsafeness = tmp;
+ }
+ return unsafeness;
default:
- return 0;
+ return 2;
}
}
\f
extern void (*lang_unsave) PARAMS ((tree *));
extern void (*lang_unsave_expr_now) PARAMS ((tree));
-/* If non-null, a language specific version of safe_for_unsave. */
-extern int (*lang_safe_for_unsave) PARAMS ((tree));
-
-/* Return nonzero if it is safe to unsave EXPR, else return zero.
- It is not safe to unsave EXPR if it contains any embedded RTL_EXPRs. */
-extern int safe_for_unsave PARAMS ((tree));
+/* Return 0 if it is safe to evaluate EXPR multiple times,
+ return 1 if it is safe if EXPR is unsaved afterward, or
+ return 2 if it is completely unsafe. */
+extern int unsafe_for_reeval PARAMS ((tree));
/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
or offset that depends on a field within a record.