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  <rguent...@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);
+ }

Reply via email to