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]
Other format: [Raw text]

[PATCH] Fix PR56982, handle setjmp like non-local labels


This fixes PR56982 by properly modeling the control-flow
of setjmp.  It basically behaves as a non-local goto target
so this patch treats it so - it makes it start a basic-block
and get abnormal edges from possible sources of non-local
gotos.  The patch also fixes the bug that longjmp is marked
as "leaf".

Bootstrapped and tested on x86_64-unknown-linux-gnu, ok for trunk?
What about release branches (after it had some time to settle on
trunk of course)?

Thanks,
Richard.

2013-04-17  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/56982
	* builtins.def (BUILT_IN_LONGJMP): longjmp is not a leaf
	function.
	* gimplify.c (gimplify_call_expr): Notice special calls.
	(gimplify_modify_expr): Likewise.
	* tree-cfg.c (make_abnormal_goto_edges): Handle setjmp-like
	abnormal control flow receivers.
	(call_can_make_abnormal_goto): Handle cfun->calls_setjmp
	in the same way as cfun->has_nonlocal_labels.
	(gimple_purge_dead_abnormal_call_edges): Likewise.
	(stmt_starts_bb_p): Make setjmp-like abnormal control flow
	receivers start a basic-block.

	* gcc.c-torture/execute/pr56982.c: New testcase.

Index: gcc/gimplify.c
===================================================================
*** gcc/gimplify.c	(revision 198021)
--- gcc/gimplify.c	(working copy)
*************** gimplify_call_expr (tree *expr_p, gimple
*** 2729,2734 ****
--- 2729,2735 ----
        gimple_stmt_iterator gsi;
        call = gimple_build_call_from_tree (*expr_p);
        gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
+       notice_special_calls (call);
        gimplify_seq_add_stmt (pre_p, call);
        gsi = gsi_last (*pre_p);
        fold_stmt (&gsi);
*************** gimplify_modify_expr (tree *expr_p, gimp
*** 4968,4973 ****
--- 4969,4975 ----
        STRIP_USELESS_TYPE_CONVERSION (CALL_EXPR_FN (*from_p));
        assign = gimple_build_call_from_tree (*from_p);
        gimple_call_set_fntype (assign, TREE_TYPE (fnptrtype));
+       notice_special_calls (assign);
        if (!gimple_call_noreturn_p (assign))
  	gimple_call_set_lhs (assign, *to_p);
      }
Index: gcc/tree-cfg.c
===================================================================
*** gcc/tree-cfg.c	(revision 198021)
--- gcc/tree-cfg.c	(working copy)
*************** make_abnormal_goto_edges (basic_block bb
*** 967,991 ****
    gimple_stmt_iterator gsi;
  
    FOR_EACH_BB (target_bb)
!     for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
!       {
! 	gimple label_stmt = gsi_stmt (gsi);
! 	tree target;
  
! 	if (gimple_code (label_stmt) != GIMPLE_LABEL)
! 	  break;
  
! 	target = gimple_label_label (label_stmt);
  
! 	/* Make an edge to every label block that has been marked as a
! 	   potential target for a computed goto or a non-local goto.  */
! 	if ((FORCED_LABEL (target) && !for_call)
! 	    || (DECL_NONLOCAL (target) && for_call))
! 	  {
  	    make_edge (bb, target_bb, EDGE_ABNORMAL);
! 	    break;
! 	  }
!       }
  }
  
  /* Create edges for a goto statement at block BB.  */
--- 971,1005 ----
    gimple_stmt_iterator gsi;
  
    FOR_EACH_BB (target_bb)
!     {
!       for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi))
! 	{
! 	  gimple label_stmt = gsi_stmt (gsi);
! 	  tree target;
  
! 	  if (gimple_code (label_stmt) != GIMPLE_LABEL)
! 	    break;
  
! 	  target = gimple_label_label (label_stmt);
  
! 	  /* Make an edge to every label block that has been marked as a
! 	     potential target for a computed goto or a non-local goto.  */
! 	  if ((FORCED_LABEL (target) && !for_call)
! 	      || (DECL_NONLOCAL (target) && for_call))
! 	    {
! 	      make_edge (bb, target_bb, EDGE_ABNORMAL);
! 	      break;
! 	    }
! 	}
!       if (!gsi_end_p (gsi))
! 	{
! 	  /* Make an edge to every setjmp-like call.  */
! 	  gimple call_stmt = gsi_stmt (gsi);
! 	  if (is_gimple_call (call_stmt)
! 	      && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE))
  	    make_edge (bb, target_bb, EDGE_ABNORMAL);
! 	}
!     }
  }
  
  /* Create edges for a goto statement at block BB.  */
*************** call_can_make_abnormal_goto (gimple t)
*** 2147,2153 ****
  {
    /* If the function has no non-local labels, then a call cannot make an
       abnormal transfer of control.  */
!   if (!cfun->has_nonlocal_label)
     return false;
  
    /* Likewise if the call has no side effects.  */
--- 2161,2168 ----
  {
    /* If the function has no non-local labels, then a call cannot make an
       abnormal transfer of control.  */
!   if (!cfun->has_nonlocal_label
!       && !cfun->calls_setjmp)
     return false;
  
    /* Likewise if the call has no side effects.  */
*************** stmt_starts_bb_p (gimple stmt, gimple pr
*** 2302,2307 ****
--- 2317,2327 ----
        else
  	return true;
      }
+   else if (gimple_code (stmt) == GIMPLE_CALL
+ 	   && gimple_call_flags (stmt) & ECF_RETURNS_TWICE)
+     /* setjmp acts similar to a nonlocal GOTO target and thus should
+        start a new block.  */
+     return true;
  
    return false;
  }
*************** gimple_purge_dead_abnormal_call_edges (b
*** 7532,7538 ****
    edge_iterator ei;
    gimple stmt = last_stmt (bb);
  
!   if (!cfun->has_nonlocal_label)
      return false;
  
    if (stmt && stmt_can_make_abnormal_goto (stmt))
--- 7568,7575 ----
    edge_iterator ei;
    gimple stmt = last_stmt (bb);
  
!   if (!cfun->has_nonlocal_label
!       && !cfun->calls_setjmp)
      return false;
  
    if (stmt && stmt_can_make_abnormal_goto (stmt))
Index: gcc/builtins.def
===================================================================
*** gcc/builtins.def	(revision 198021)
--- gcc/builtins.def	(working copy)
*************** DEF_GCC_BUILTIN        (BUILT_IN_ISLESSG
*** 715,721 ****
  DEF_GCC_BUILTIN        (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
  DEF_LIB_BUILTIN        (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_C99_BUILTIN        (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
! DEF_GCC_BUILTIN        (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LEAF_LIST)
  /* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed.  */
  DEF_LIB_BUILTIN        (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
--- 715,721 ----
  DEF_GCC_BUILTIN        (BUILT_IN_ISUNORDERED, "isunordered", BT_FN_INT_VAR, ATTR_CONST_NOTHROW_TYPEGENERIC_LEAF)
  DEF_LIB_BUILTIN        (BUILT_IN_LABS, "labs", BT_FN_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
  DEF_C99_BUILTIN        (BUILT_IN_LLABS, "llabs", BT_FN_LONGLONG_LONGLONG, ATTR_CONST_NOTHROW_LEAF_LIST)
! DEF_GCC_BUILTIN        (BUILT_IN_LONGJMP, "longjmp", BT_FN_VOID_PTR_INT, ATTR_NORETURN_NOTHROW_LIST)
  /* [trans-mem]: Adjust BUILT_IN_TM_MALLOC if BUILT_IN_MALLOC is changed.  */
  DEF_LIB_BUILTIN        (BUILT_IN_MALLOC, "malloc", BT_FN_PTR_SIZE, ATTR_MALLOC_NOTHROW_LEAF_LIST)
  DEF_GCC_BUILTIN        (BUILT_IN_NEXT_ARG, "next_arg", BT_FN_PTR_VAR, ATTR_LEAF_LIST)
Index: gcc/testsuite/gcc.c-torture/execute/pr56982.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr56982.c	(revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr56982.c	(working copy)
***************
*** 0 ****
--- 1,43 ----
+ #include <stdlib.h>
+ #include <setjmp.h>
+ 
+ static sigjmp_buf env;
+ void *stderr;
+ void baz (void)
+ {
+   __asm__ volatile ("" : : : "memory");
+ }
+ 
+ static inline int g(int x)
+ {
+     if (x)
+     {
+         baz();
+         return 0;
+     }
+     else
+     {
+         baz();
+         return 1;
+     }
+ }
+ 
+ int f(int *e)
+ {
+     if (*e)
+       return 1;
+ 
+     int x = setjmp(env);
+     int n = g(x);
+     if (n == 0)
+       exit(0);
+     if (x)
+       abort();
+     longjmp(env, 42);
+ }
+ 
+ int main(int argc, char** argv)
+ {
+     int v = 0;
+     return f(&v);
+ }


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