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]

Re: Optimization bug


On Sat, Aug 12, 2000 at 12:44:18AM +0200, Carlo Wood wrote:
> The problem is gcc is confused near `return' with its local variables
> on the stack: returning from a function exits the scope of the local
> variables, so that when a recursive call to the same function is
> performed, this call is replaced by a jmp to the start of the function
> and the same stack space is used for the local variables.

A similar test case already exists: gcc.c-torture/execute/20000412-2.c.

Fixed thus.  Tested on i686-linux.


r~

        * sibcall.c (uses_addressof): Accept both addressof and
        current_function_internal_arg_pointer inside a mem.
        (optimize_sibling_and_tail_recursive_call): Fail tail recursion
        if current_function_uses_addressof.
        * stmt.c (expand_return): Kill tail recursion and HAVE_return
        optimizations.

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

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