tree.c (lang_safe_for_unsave): Remove.

* tree.c (lang_safe_for_unsave): Remove.
        (unsafe_for_reeval): Transmute and rename from safe_for_unsave,
        allowing for two levels of unsafeness.  Remove lang hook.
        * tree.h: Update declarations.
        * calls.c (expand_call): Rename safe_for_reeval to try_tail_call.
        Create temporary VAR_DECLs to protect very unsafe_for_reeval trees.
        Always fail sibcalls when there are pending cleanups.

From-SVN: r32735
This commit is contained in:
Richard Henderson 2000-03-24 17:06:35 -08:00 committed by Richard Henderson
parent 1c33f70c96
commit 194c7c45b1
4 changed files with 112 additions and 61 deletions

View File

@ -1,3 +1,13 @@
2000-03-24 Richard Henderson <rth@cygnus.com>
* tree.c (lang_safe_for_unsave): Remove.
(unsafe_for_reeval): Transmute and rename from safe_for_unsave,
allowing for two levels of unsafeness. Remove lang hook.
* tree.h: Update declarations.
* calls.c (expand_call): Rename safe_for_reeval to try_tail_call.
Create temporary VAR_DECLs to protect very unsafe_for_reeval trees.
Always fail sibcalls when there are pending cleanups.
2000-03-24 Geoff Keating <geoffk@cygnus.com>
* flow.c (propagate_block): When we delete an ADDR_VEC,

View File

@ -1696,7 +1696,7 @@ expand_call (exp, target, ignore)
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,
@ -2027,44 +2027,70 @@ expand_call (exp, target, ignore)
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)
{
@ -2149,7 +2175,7 @@ expand_call (exp, target, ignore)
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
@ -2163,6 +2189,10 @@ expand_call (exp, target, ignore)
/* 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;
@ -2819,10 +2849,13 @@ expand_call (exp, target, ignore)
/* 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)

View File

@ -290,9 +290,6 @@ static void print_type_hash_statistics PARAMS((void));
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. */
@ -2675,15 +2672,28 @@ unsave_expr_now (expr)
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)
@ -2691,10 +2701,13 @@ safe_for_unsave (expr)
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)
@ -2703,26 +2716,20 @@ safe_for_unsave (expr)
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;
}
@ -2733,7 +2740,7 @@ safe_for_unsave (expr)
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 */
@ -2742,12 +2749,15 @@ safe_for_unsave (expr)
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;
}
}

View File

@ -1963,12 +1963,10 @@ extern tree unsave_expr_now PARAMS ((tree));
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.