This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

sibcall fixup


This is a continuation of the fix where sibcall wasn't properly checking
for the end of block.  I also got rid of the gotos in the code in
question (yes, I understand that some might consider the replacement worse ..).

Tested on alphaev56.

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.

*** sibcall.c	2000/10/24 11:25:50	1.10
--- sibcall.c	2001/02/18 23:58:07
*************** optimize_sibling_and_tail_recursive_call
*** 534,539 ****
  	  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;
  
  	  /* We must be careful with stack slots which are live at
--- 534,539 ----
  	  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
*************** optimize_sibling_and_tail_recursive_call
*** 541,552 ****
  
  	     ?!? 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;
- 
  	  /* alloca (until we have stack slot life analysis) inhibits
  	     sibling call optimizations, but not tail recursion.
--- 541,550 ----
  
  	     ?!? 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;
  
  	  /* alloca (until we have stack slot life analysis) inhibits
  	     sibling call optimizations, but not tail recursion.
*************** optimize_sibling_and_tail_recursive_call
*** 557,627 ****
  	    sibcall = 0;
  
  	  call_block = BLOCK_FOR_INSN (insn);
  
  	  /* If the block has more than one successor, then we can not
! 	     perform sibcall or tail recursion optimizations.  */
  	  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:
- 
  	  /* 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, 
--- 555,609 ----
  	    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
! 	      || 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, 


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]