From: Richard Kenner Date: Mon, 19 Feb 2001 13:27:36 +0000 (+0000) Subject: sibcall.c (call_ends_block_p): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=e5c617ff163919020a7125ec43c0b59f84275486;p=gcc.git sibcall.c (call_ends_block_p): New function. * sibcall.c (call_ends_block_p): New function. (optimize_sibling_and_tail_recursive_call): Use it. From-SVN: r39879 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 29a8e4dfafc..be525f1a1ba 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +Mon Feb 19 08:27:21 2001 Richard Kenner + + * sibcall.c (call_ends_block_p): New function. + (optimize_sibling_and_tail_recursive_call): Use it. + 2001-02-18 Kazu Hirata * config/h8300/h8300.md: Update copyright. diff --git a/gcc/sibcall.c b/gcc/sibcall.c index debefc70992..c599a8eac18 100644 --- a/gcc/sibcall.c +++ b/gcc/sibcall.c @@ -1,5 +1,5 @@ /* Generic sibling call optimization support - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. This file is part of GNU CC. @@ -38,6 +38,7 @@ static rtx skip_use_of_return_value PARAMS ((rtx, enum rtx_code)); static rtx skip_stack_adjustment PARAMS ((rtx)); static rtx skip_pic_restore PARAMS ((rtx)); static rtx skip_jump_insn PARAMS ((rtx)); +static int call_ends_block_p PARAMS ((rtx, rtx)); static int uses_addressof PARAMS ((rtx)); static int sequence_uses_addressof PARAMS ((rtx)); static void purge_reg_equiv_notes PARAMS ((void)); @@ -255,6 +256,52 @@ skip_jump_insn (orig_insn) return orig_insn; } + +/* Using the above functions, see if INSN, skipping any of the above, + goes all the way to END, the end of a basic block. Return 1 if so. */ + +static int +call_ends_block_p (insn, end) + rtx insn; + rtx end; +{ + rtx hardret, softret; + + /* END might be a note, so get the last nonnote insn of the block. */ + end = next_nonnote_insn (PREV_INSN (end)); + + /* If the call was the end of the block, then we're OK. */ + if (insn == end) + return 1; + + /* 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); + insn = skip_copy_to_return_value (insn, hardret, softret); + if (insn == end) + return 1; + + /* Skip any stack adjustment. */ + insn = skip_stack_adjustment (insn); + if (insn == end) + return 1; + + /* Skip over a CLOBBER of the return value as a hard reg. */ + insn = skip_use_of_return_value (insn, CLOBBER); + if (insn == end) + return 1; + + /* Skip over a USE of the return value (as a hard reg). */ + insn = skip_use_of_return_value (insn, USE); + if (insn == end) + return 1; + + /* Skip over a JUMP_INSN at the end of the block. If that doesn't end the + block, the original CALL_INSN didn't. */ + insn = skip_jump_insn (insn); + return insn == end; +} /* Scan the rtx X for ADDRESSOF expressions or current_function_internal_arg_pointer registers. @@ -533,18 +580,7 @@ optimize_sibling_and_tail_recursive_calls () { int sibcall = (XEXP (PATTERN (insn), 1) != NULL_RTX); int tailrecursion = (XEXP (PATTERN (insn), 2) != NULL_RTX); - 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 - /* 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; + basic_block call_block = BLOCK_FOR_INSN (insn); /* alloca (until we have stack slot life analysis) inhibits sibling call optimizations, but not tail recursion. @@ -554,49 +590,23 @@ 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. 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 + /* See if there are any reasons we can't perform either sibling or + tail call optimizations. 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 + /* Can't take address of local var if used by recursive call. */ + || current_function_uses_addressof + /* Can't if more than one successor or single successor is not + exit block. These two tests prevent tail call optimization + in the presense of active exception handlers. */ + || call_block->succ == NULL || 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. */ + && call_block->succ->dest != alternate_exit) + /* If this call doesn't end the block, there are operations at + the end of the block which we must execute after returning. */ + || ! call_ends_block_p (insn, call_block->end)) sibcall = 0, tailrecursion = 0; /* Select a set of insns to implement the call and emit them.