exit(0) is miscompiled under i686 linux

Richard Henderson rth@cygnus.com
Sat Oct 7 14:03:00 GMT 2000


On Fri, Oct 06, 2000 at 07:42:57PM -0400, John David Anglin wrote:
> With todays cvs, I experienced failure of the first rdbz test in the
> libio testsuite.  Tracking this, I find that the `exit(0);' statement
> in rdbzmain.c compiles to:
> 
>         movl    $0, 8(%ebp)
> 	jmp     exit
> 
> with -O2 or -O3.  As a result, the exit status value is garbage.

This is the fault of my noreturn patch -- sibcalls to noreturn
functions no longer got an edge to EXIT, which meant that the
code intended to insert sibcall_epilogue patterns didn't.

It's a quandry: we need the more accurate CFG for the "control
reaches end of non-void function" test.  But then if we brute
force search for sibcalls to insert the sibcall_epilogue 
patterns, we'll wind up with flow2 warning about wanting to
delete dead epilogue code (the loads for the call-saved registers
are dead becase we don't return).

I think the best way to solve this is to not create sibcalls
to noreturn functions.  This is a pessimization for functions
that would otherwise be leaf functions, but a win otherwise,
since the epilogue code is usually larger than the call.


r~


        * calls.c (expand_call): Disallow sibcalls to noreturn functions.
        * flow.c (make_edges): Revert last change.

        * config/alpha/alpha.h (FUNCTION_OK_FOR_SIBCALL): Don't test
        TREE_THIS_VOLATILE.
        * config/pa/pa.h (FUNCTION_OK_FOR_SIBCALL): Likewise.

Index: calls.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/calls.c,v
retrieving revision 1.158
diff -c -p -d -r1.158 calls.c
*** calls.c	2000/09/17 12:45:49	1.158
--- calls.c	2000/10/07 20:50:22
*************** expand_call (exp, target, ignore)
*** 2463,2468 ****
--- 2463,2469 ----
  	 before the sibcall_epilogue.  */
        || fndecl == NULL_TREE
        || (flags & (ECF_RETURNS_TWICE | ECF_LONGJMP))
+       || TREE_THIS_VOLATILE (fndecl)
        || !FUNCTION_OK_FOR_SIBCALL (fndecl)
        /* If this function requires more stack slots than the current
  	 function, we cannot change it into a sibling call.  */
Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.342
diff -c -p -d -r1.342 flow.c
*** flow.c	2000/10/06 06:01:26	1.342
--- flow.c	2000/10/07 20:50:23
*************** make_edges (label_value_list)
*** 1152,1163 ****
  	 wouldn't have created the sibling call in the first place.  */
  
        if (code == CALL_INSN && SIBLING_CALL_P (insn))
! 	{
! 	  if (! find_reg_note (insn, REG_NORETURN, NULL_RTX))
! 	    make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
! 		       EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
! 	}
!       else
  
        /* If this is a CALL_INSN, then mark it as reaching the active EH
  	 handler for this CALL_INSN.  If we're handling asynchronous
--- 1152,1159 ----
  	 wouldn't have created the sibling call in the first place.  */
  
        if (code == CALL_INSN && SIBLING_CALL_P (insn))
! 	make_edge (edge_cache, bb, EXIT_BLOCK_PTR,
! 		   EDGE_ABNORMAL | EDGE_ABNORMAL_CALL);
  
        /* If this is a CALL_INSN, then mark it as reaching the active EH
  	 handler for this CALL_INSN.  If we're handling asynchronous
*************** make_edges (label_value_list)
*** 1165,1171 ****
  
  	 Also mark the CALL_INSN as reaching any nonlocal goto handler.  */
  
!       if (code == CALL_INSN || asynchronous_exceptions)
  	{
  	  /* Add any appropriate EH edges.  We do this unconditionally
  	     since there may be a REG_EH_REGION or REG_EH_RETHROW note
--- 1161,1167 ----
  
  	 Also mark the CALL_INSN as reaching any nonlocal goto handler.  */
  
!       else if (code == CALL_INSN || asynchronous_exceptions)
  	{
  	  /* Add any appropriate EH edges.  We do this unconditionally
  	     since there may be a REG_EH_REGION or REG_EH_RETHROW note
Index: config/alpha/alpha.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/alpha/alpha.h,v
retrieving revision 1.106
diff -c -p -d -r1.106 alpha.h
*** alpha.h	2000/10/02 08:21:35	1.106
--- alpha.h	2000/10/07 20:50:42
*************** extern int alpha_memory_latency;
*** 1187,1194 ****
  #define FUNCTION_OK_FOR_SIBCALL(DECL)			\
    (DECL							\
     && ((TREE_ASM_WRITTEN (DECL) && !flag_pic)		\
!        || ! TREE_PUBLIC (DECL)				\
!        || (0 && TREE_THIS_VOLATILE (DECL))))
  
  /* Try to output insns to set TARGET equal to the constant C if it can be
     done in less than N insns.  Do all computations in MODE.  Returns the place
--- 1187,1193 ----
  #define FUNCTION_OK_FOR_SIBCALL(DECL)			\
    (DECL							\
     && ((TREE_ASM_WRITTEN (DECL) && !flag_pic)		\
!        || ! TREE_PUBLIC (DECL)))
  
  /* Try to output insns to set TARGET equal to the constant C if it can be
     done in less than N insns.  Do all computations in MODE.  Returns the place
Index: config/pa/pa.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/pa/pa.h,v
retrieving revision 1.93
diff -c -p -d -r1.93 pa.h
*** pa.h	2000/09/25 10:11:22	1.93
--- pa.h	2000/10/07 20:50:43
*************** while (0)
*** 2014,2021 ****
  #define FUNCTION_OK_FOR_SIBCALL(DECL) \
    (DECL \
     && ! TARGET_64BIT \
!    && (! TREE_PUBLIC (DECL) \
!        || TREE_THIS_VOLATILE (DECL)))
  
  #define PREDICATE_CODES							\
    {"reg_or_0_operand", {SUBREG, REG, CONST_INT}},			\
--- 2014,2020 ----
  #define FUNCTION_OK_FOR_SIBCALL(DECL) \
    (DECL \
     && ! TARGET_64BIT \
!    && ! TREE_PUBLIC (DECL))
  
  #define PREDICATE_CODES							\
    {"reg_or_0_operand", {SUBREG, REG, CONST_INT}},			\


More information about the Gcc-patches mailing list