sibcall.c (optimize_sibling_and_tail_recursive_call): Compare against last real insn in basic block.

* sibcall.c (optimize_sibling_and_tail_recursive_call): Compare
	against last real insn in basic block.
	Rework to avoid gotos.

From-SVN: r39858
This commit is contained in:
Richard Kenner 2001-02-19 00:00:08 +00:00 committed by Richard Kenner
parent fb0c0a1270
commit 021921d0e4
2 changed files with 52 additions and 66 deletions

View File

@ -1,5 +1,9 @@
Sun Feb 18 15:45:17 2001 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* sibcall.c (optimize_sibling_and_tail_recursive_call): Compare
against last real insn in basic block.
Rework to avoid gotos.
* Makefile.in (gcse.o): Now includes ggc.h.
* gcse.c: Include ggc.h.
(want_to_gcse_p): Verify expression can be in SET as valid insn.

View File

@ -533,20 +533,18 @@ optimize_sibling_and_tail_recursive_calls ()
{
int sibcall = (XEXP (PATTERN (insn), 1) != NULL_RTX);
int tailrecursion = (XEXP (PATTERN (insn), 2) != NULL_RTX);
basic_block succ_block, call_block;
rtx temp, hardret, softret;
basic_block call_block;
rtx end, temp, hardret, softret;
/* We must be careful with stack slots which are live at
potential optimization sites.
?!? This test is overly conservative and will be replaced. */
if (frame_offset)
goto failure;
/* Taking the address of a local variable is fatal to tail
recursion if the address is used by the recursive call. */
if (current_function_uses_addressof)
goto failure;
if (frame_offset
/* Taking the address of a local variable is fatal to tail
recursion if the address is used by the recursive call. */
|| current_function_uses_addressof)
sibcall = 0, tailrecursion = 0;
/* alloca (until we have stack slot life analysis) inhibits
sibling call optimizations, but not tail recursion.
@ -556,73 +554,57 @@ optimize_sibling_and_tail_recursive_calls ()
|| current_function_varargs || current_function_stdarg)
sibcall = 0;
/* Get the block for the call and the last non-note insn in it. We
take advantage of the fact that this cannot be the exit block. */
call_block = BLOCK_FOR_INSN (insn);
end = prev_nonnote_insn (NEXT_INSN (call_block->end));
/* If the block has more than one successor, then we can not
perform sibcall or tail recursion optimizations. */
perform sibcall or tail recursion optimizations. If the single
successor is not the exit block, then we can not perform sibcall
or tail recursion optimizations. Note that these two tests
combined are sufficient to prevent tail call optimization in the
presense of active exception handlers. */
if (call_block->succ == NULL
|| call_block->succ->succ_next != NULL)
goto failure;
/* If the single successor is not the exit block, then we can not
perform sibcall or tail recursion optimizations.
Note that this test combined with the previous is sufficient
to prevent tail call optimization in the presense of active
exception handlers. */
succ_block = call_block->succ->dest;
if (succ_block != EXIT_BLOCK_PTR && succ_block != alternate_exit)
goto failure;
/* If the call was the end of the block, then we're OK. */
temp = insn;
if (temp == call_block->end)
goto success;
/* Skip over copying from the call's return value pseudo into
this function's hard return register. */
if (identify_call_return_value (PATTERN (insn), &hardret, &softret))
{
temp = skip_copy_to_return_value (temp, hardret, softret);
if (temp == call_block->end)
goto success;
}
/* Skip any stack adjustment. */
temp = skip_stack_adjustment (temp);
if (temp == call_block->end)
goto success;
/* Skip over a CLOBBER of the return value (as a hard reg). */
temp = skip_use_of_return_value (temp, CLOBBER);
if (temp == call_block->end)
goto success;
/* Skip over a USE of the return value (as a hard reg). */
temp = skip_use_of_return_value (temp, USE);
if (temp == call_block->end)
goto success;
/* Skip over the JUMP_INSN at the end of the block. */
temp = skip_jump_insn (temp);
if (GET_CODE (temp) == NOTE)
temp = next_nonnote_insn (temp);
if (temp == call_block->end)
goto success;
/* There are operations at the end of the block which we must
execute after returning from the function call. So this call
can not be optimized. */
failure:
sibcall = 0, tailrecursion = 0;
success:
|| call_block->succ->succ_next != NULL
|| (call_block->succ->dest != EXIT_BLOCK_PTR
&& call_block->succ->dest != alternate_exit))
sibcall = 0, tailrecursion = 0;
/* If we haven't failed yet, check if this (or safe things) ends our
block. */
if ((sibcall || tailrecursion)
/* If the call was the end of the block, then we're OK. */
&& (end == (temp = insn)
/* Skip over copying from the call's return value pseudo into
this function's hard return register and if that's the end
of the block, we're OK. */
|| (identify_call_return_value (PATTERN (insn), &hardret,
&softret)
&& end == (temp = skip_copy_to_return_value (insn,
hardret,
softret)))
/* Skip any stack adjustment. */
|| end == (temp = skip_stack_adjustment (temp))
/* Skip over a CLOBBER of the return value as a hard reg. */
|| end == (temp = skip_use_of_return_value (temp, CLOBBER))
/* Skip over a USE of the return value (as a hard reg). */
|| end == (temp = skip_use_of_return_value (temp, USE))
/* Skip over the JUMP_INSN at the end of the block. */
|| end == (temp = skip_jump_insn (temp))))
;
else
/* There are operations at the end of the block which we must
execute after returning from the function call. So this call
can not be optimized. */
sibcall = 0, tailrecursion = 0;
/* Select a set of insns to implement the call and emit them.
Tail recursion is the most efficient, so select it over
a tail/sibling call. */
if (sibcall)
successful_sibling_call = 1;
replaced_call_placeholder = 1;
replace_call_placeholder (insn,
tailrecursion != 0