01e27f8
2000-08-12  Richard Henderson  <rth@cygnus.com>
01e27f8
01e27f8
        * sibcall.c (uses_addressof): Accept both addressof and
01e27f8
        current_function_internal_arg_pointer inside a mem.
01e27f8
        (optimize_sibling_and_tail_recursive_call): Fail tail recursion
01e27f8
        if current_function_uses_addressof.
01e27f8
        * stmt.c (expand_return): Kill tail recursion and HAVE_return
01e27f8
        optimizations.
01e27f8
01e27f8
*** gcc/sibcall.c	2000/08/04 20:28:06	1.7
01e27f8
--- gcc/sibcall.c	2000/08/12 16:24:33
01e27f8
*************** static rtx skip_copy_to_return_value	PAR
01e27f8
*** 37,43 ****
01e27f8
  static rtx skip_use_of_return_value	PARAMS ((rtx, enum rtx_code));
01e27f8
  static rtx skip_stack_adjustment	PARAMS ((rtx));
01e27f8
  static rtx skip_jump_insn		PARAMS ((rtx));
01e27f8
! static int uses_addressof		PARAMS ((rtx, int));
01e27f8
  static int sequence_uses_addressof	PARAMS ((rtx));
01e27f8
  static void purge_reg_equiv_notes	PARAMS ((void));
01e27f8
  
01e27f8
--- 37,43 ----
01e27f8
  static rtx skip_use_of_return_value	PARAMS ((rtx, enum rtx_code));
01e27f8
  static rtx skip_stack_adjustment	PARAMS ((rtx));
01e27f8
  static rtx skip_jump_insn		PARAMS ((rtx));
01e27f8
! static int uses_addressof		PARAMS ((rtx));
01e27f8
  static int sequence_uses_addressof	PARAMS ((rtx));
01e27f8
  static void purge_reg_equiv_notes	PARAMS ((void));
01e27f8
  
01e27f8
*************** skip_jump_insn (orig_insn)
01e27f8
*** 237,252 ****
01e27f8
  
01e27f8
  /* Scan the rtx X for ADDRESSOF expressions or
01e27f8
     current_function_internal_arg_pointer registers.
01e27f8
!    INMEM argument should be 1 if we're looking at inner part of some
01e27f8
!    MEM expression, otherwise 0.
01e27f8
!    Return nonzero if an ADDRESSOF expresion is found or if
01e27f8
!    current_function_internal_arg_pointer is found outside of some MEM
01e27f8
!    expression, else return zero.  */
01e27f8
  
01e27f8
  static int
01e27f8
! uses_addressof (x, inmem)
01e27f8
       rtx x;
01e27f8
-      int inmem;
01e27f8
  {
01e27f8
    RTX_CODE code;
01e27f8
    int i, j;
01e27f8
--- 237,248 ----
01e27f8
  
01e27f8
  /* Scan the rtx X for ADDRESSOF expressions or
01e27f8
     current_function_internal_arg_pointer registers.
01e27f8
!    Return nonzero if an ADDRESSOF or current_function_internal_arg_pointer
01e27f8
!    is found outside of some MEM expression, else return zero.  */
01e27f8
  
01e27f8
  static int
01e27f8
! uses_addressof (x)
01e27f8
       rtx x;
01e27f8
  {
01e27f8
    RTX_CODE code;
01e27f8
    int i, j;
01e27f8
*************** uses_addressof (x, inmem)
01e27f8
*** 256,270 ****
01e27f8
      return 0;
01e27f8
  
01e27f8
    code = GET_CODE (x);
01e27f8
- 
01e27f8
-   if (code == ADDRESSOF)
01e27f8
-     return 1;
01e27f8
  
01e27f8
!   if (x == current_function_internal_arg_pointer && ! inmem)
01e27f8
      return 1;
01e27f8
  
01e27f8
    if (code == MEM)
01e27f8
!     return uses_addressof (XEXP (x, 0), 1);
01e27f8
  
01e27f8
    /* Scan all subexpressions. */
01e27f8
    fmt = GET_RTX_FORMAT (code);
01e27f8
--- 252,263 ----
01e27f8
      return 0;
01e27f8
  
01e27f8
    code = GET_CODE (x);
01e27f8
  
01e27f8
!   if (code == ADDRESSOF || x == current_function_internal_arg_pointer)
01e27f8
      return 1;
01e27f8
  
01e27f8
    if (code == MEM)
01e27f8
!     return 0;
01e27f8
  
01e27f8
    /* Scan all subexpressions. */
01e27f8
    fmt = GET_RTX_FORMAT (code);
01e27f8
*************** uses_addressof (x, inmem)
01e27f8
*** 272,284 ****
01e27f8
      {
01e27f8
        if (*fmt == 'e')
01e27f8
  	{
01e27f8
! 	  if (uses_addressof (XEXP (x, i), inmem))
01e27f8
  	    return 1;
01e27f8
  	}
01e27f8
        else if (*fmt == 'E')
01e27f8
  	{
01e27f8
  	  for (j = 0; j < XVECLEN (x, i); j++)
01e27f8
! 	    if (uses_addressof (XVECEXP (x, i, j), inmem))
01e27f8
  	      return 1;
01e27f8
  	}
01e27f8
      }
01e27f8
--- 265,277 ----
01e27f8
      {
01e27f8
        if (*fmt == 'e')
01e27f8
  	{
01e27f8
! 	  if (uses_addressof (XEXP (x, i)))
01e27f8
  	    return 1;
01e27f8
  	}
01e27f8
        else if (*fmt == 'E')
01e27f8
  	{
01e27f8
  	  for (j = 0; j < XVECLEN (x, i); j++)
01e27f8
! 	    if (uses_addressof (XVECEXP (x, i, j)))
01e27f8
  	      return 1;
01e27f8
  	}
01e27f8
      }
01e27f8
*************** sequence_uses_addressof (seq)
01e27f8
*** 318,325 ****
01e27f8
  		&& sequence_uses_addressof (XEXP (PATTERN (insn), 2)))
01e27f8
  	      return 1;
01e27f8
  	  }
01e27f8
! 	else if (uses_addressof (PATTERN (insn), 0)
01e27f8
! 		 || (REG_NOTES (insn) && uses_addressof (REG_NOTES (insn), 0)))
01e27f8
  	  return 1;
01e27f8
        }
01e27f8
    return 0;
01e27f8
--- 311,318 ----
01e27f8
  		&& sequence_uses_addressof (XEXP (PATTERN (insn), 2)))
01e27f8
  	      return 1;
01e27f8
  	  }
01e27f8
! 	else if (uses_addressof (PATTERN (insn))
01e27f8
! 		 || (REG_NOTES (insn) && uses_addressof (REG_NOTES (insn))))
01e27f8
  	  return 1;
01e27f8
        }
01e27f8
    return 0;
01e27f8
*************** optimize_sibling_and_tail_recursive_call
01e27f8
*** 490,503 ****
01e27f8
  	  if (frame_offset)
01e27f8
  	    goto failure;
01e27f8
  
01e27f8
  	  /* alloca (until we have stack slot life analysis) inhibits
01e27f8
  	     sibling call optimizations, but not tail recursion.
01e27f8
- 
01e27f8
- 	     Similarly if we have ADDRESSOF expressions.
01e27f8
- 
01e27f8
  	     Similarly if we use varargs or stdarg since they implicitly
01e27f8
  	     may take the address of an argument.  */
01e27f8
!  	  if (current_function_calls_alloca || current_function_uses_addressof
01e27f8
  	      || current_function_varargs || current_function_stdarg)
01e27f8
  	    sibcall = 0;
01e27f8
  
01e27f8
--- 483,498 ----
01e27f8
  	  if (frame_offset)
01e27f8
  	    goto failure;
01e27f8
  
01e27f8
+ 	  /* Taking the address of a local variable is fatal to tail
01e27f8
+ 	     recursion if the address is used by the recursive call.  */
01e27f8
+ 	  if (current_function_uses_addressof)
01e27f8
+ 	    goto failure;
01e27f8
+ 
01e27f8
  	  /* alloca (until we have stack slot life analysis) inhibits
01e27f8
  	     sibling call optimizations, but not tail recursion.
01e27f8
  	     Similarly if we use varargs or stdarg since they implicitly
01e27f8
  	     may take the address of an argument.  */
01e27f8
!  	  if (current_function_calls_alloca
01e27f8
  	      || current_function_varargs || current_function_stdarg)
01e27f8
  	    sibcall = 0;
01e27f8
  
01e27f8
*** gcc/stmt.c	2000/08/06 10:07:30	1.156
01e27f8
--- gcc/stmt.c	2000/08/12 16:24:33
01e27f8
*************** expand_return (retval)
01e27f8
*** 2809,2817 ****
01e27f8
    rtx last_insn = 0;
01e27f8
    rtx result_rtl = DECL_RTL (DECL_RESULT (current_function_decl));
01e27f8
    register rtx val = 0;
01e27f8
- #ifdef HAVE_return
01e27f8
-   register rtx op0;
01e27f8
- #endif
01e27f8
    tree retval_rhs;
01e27f8
    int cleanups;
01e27f8
  
01e27f8
--- 2809,2814 ----
01e27f8
*************** expand_return (retval)
01e27f8
*** 2884,2965 ****
01e27f8
        end_cleanup_deferral ();
01e27f8
        return;
01e27f8
      }
01e27f8
- 
01e27f8
-   /* Attempt to optimize the call if it is tail recursive.  */
01e27f8
-   if (flag_optimize_sibling_calls
01e27f8
-       && retval_rhs != NULL_TREE
01e27f8
-       && frame_offset == 0
01e27f8
-       && TREE_CODE (retval_rhs) == CALL_EXPR
01e27f8
-       && TREE_CODE (TREE_OPERAND (retval_rhs, 0)) == ADDR_EXPR
01e27f8
-       && (TREE_OPERAND (TREE_OPERAND (retval_rhs, 0), 0)
01e27f8
- 	  == current_function_decl)
01e27f8
-       && optimize_tail_recursion (TREE_OPERAND (retval_rhs, 1), last_insn))
01e27f8
-     return;
01e27f8
- 
01e27f8
- #ifdef HAVE_return
01e27f8
-   /* This optimization is safe if there are local cleanups
01e27f8
-      because expand_null_return takes care of them.
01e27f8
-      ??? I think it should also be safe when there is a cleanup label,
01e27f8
-      because expand_null_return takes care of them, too.
01e27f8
-      Any reason why not?  */
01e27f8
-   if (HAVE_return && cleanup_label == 0
01e27f8
-       && ! current_function_returns_pcc_struct
01e27f8
-       && BRANCH_COST <= 1)
01e27f8
-     {
01e27f8
-       /* If this is  return x == y;  then generate
01e27f8
- 	 if (x == y) return 1; else return 0;
01e27f8
- 	 if we can do it with explicit return insns and branches are cheap,
01e27f8
- 	 but not if we have the corresponding scc insn.  */
01e27f8
-       int has_scc = 0;
01e27f8
-       if (retval_rhs)
01e27f8
- 	switch (TREE_CODE (retval_rhs))
01e27f8
- 	  {
01e27f8
- 	  case EQ_EXPR:
01e27f8
- #ifdef HAVE_seq
01e27f8
- 	    has_scc = HAVE_seq;
01e27f8
- #endif
01e27f8
- 	  case NE_EXPR:
01e27f8
- #ifdef HAVE_sne
01e27f8
- 	    has_scc = HAVE_sne;
01e27f8
- #endif
01e27f8
- 	  case GT_EXPR:
01e27f8
- #ifdef HAVE_sgt
01e27f8
- 	    has_scc = HAVE_sgt;
01e27f8
- #endif
01e27f8
- 	  case GE_EXPR:
01e27f8
- #ifdef HAVE_sge
01e27f8
- 	    has_scc = HAVE_sge;
01e27f8
- #endif
01e27f8
- 	  case LT_EXPR:
01e27f8
- #ifdef HAVE_slt
01e27f8
- 	    has_scc = HAVE_slt;
01e27f8
- #endif
01e27f8
- 	  case LE_EXPR:
01e27f8
- #ifdef HAVE_sle
01e27f8
- 	    has_scc = HAVE_sle;
01e27f8
- #endif
01e27f8
- 	  case TRUTH_ANDIF_EXPR:
01e27f8
- 	  case TRUTH_ORIF_EXPR:
01e27f8
- 	  case TRUTH_AND_EXPR:
01e27f8
- 	  case TRUTH_OR_EXPR:
01e27f8
- 	  case TRUTH_NOT_EXPR:
01e27f8
- 	  case TRUTH_XOR_EXPR:
01e27f8
- 	    if (! has_scc)
01e27f8
- 	      {
01e27f8
- 		op0 = gen_label_rtx ();
01e27f8
- 		jumpifnot (retval_rhs, op0);
01e27f8
- 		expand_value_return (const1_rtx);
01e27f8
- 		emit_label (op0);
01e27f8
- 		expand_value_return (const0_rtx);
01e27f8
- 		return;
01e27f8
- 	      }
01e27f8
- 	    break;
01e27f8
- 
01e27f8
- 	  default:
01e27f8
- 	    break;
01e27f8
- 	  }
01e27f8
-     }
01e27f8
- #endif /* HAVE_return */
01e27f8
  
01e27f8
    /* If the result is an aggregate that is being returned in one (or more)
01e27f8
       registers, load the registers here.  The compiler currently can't handle
01e27f8
--- 2881,2886 ----
01e27f8