re PR tree-optimization/56982 (Bad optimization with setjmp())
authorRichard Biener <rguenther@suse.de>
Fri, 19 Apr 2013 13:39:16 +0000 (13:39 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 19 Apr 2013 13:39:16 +0000 (13:39 +0000)
2013-04-19  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.

From-SVN: r198096

gcc/ChangeLog
gcc/builtins.def
gcc/gimplify.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/execute/pr56982.c [new file with mode: 0644]
gcc/tree-cfg.c

index 8bdf2a9cf76b74487c734aea580040ca6f51e16d..e2aca327abe279226251ed71c4eef2d4f40dd9bf 100644 (file)
@@ -1,3 +1,18 @@
+2013-04-19  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.
+
 2013-04-19  Richard Biener  <rguenther@suse.de>
 
        * tree-vectorizer.h (struct _slp_instance): Move load_permutation
index 4f378fad60b59208882acc07f762f0c66ba02ccd..b26eb247491863145bd5efd1961d9e60fadb9992 100644 (file)
@@ -715,7 +715,7 @@ DEF_GCC_BUILTIN        (BUILT_IN_ISLESSGREATER, "islessgreater", BT_FN_INT_VAR,
 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)
+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 a93ce7c2ad272002e8fb691c286eeb8f8b6bbce6..3a90588424c99e70c9f1624ce3a33c4b0999535b 100644 (file)
@@ -2729,6 +2729,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
       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);
@@ -4968,6 +4969,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
       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 58b0fca12cef410fe0980511a0653c5458a8ec03..a31889a3b29054d675b06b1575f78793994d287b 100644 (file)
@@ -1,3 +1,8 @@
+2013-04-19  Richard Biener  <rguenther@suse.de>
+
+       PR tree-optimization/56982
+       * gcc.c-torture/execute/pr56982.c: New testcase.
+
 2013-04-19  Martin Jambor  <mjambor@suse.cz>
 
        PR tree-optimization/56718
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr56982.c b/gcc/testsuite/gcc.c-torture/execute/pr56982.c
new file mode 100644 (file)
index 0000000..371a91c
--- /dev/null
@@ -0,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 8a36976cc3b8b2d2eeadca62f10ac52549ac38ce..05bac430f50ccff4bfd48a2cc37409e07aafec4f 100644 (file)
@@ -967,25 +967,35 @@ make_abnormal_goto_edges (basic_block bb, bool for_call)
   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;
+    {
+      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;
+         if (gimple_code (label_stmt) != GIMPLE_LABEL)
+           break;
 
-       target = gimple_label_label (label_stmt);
+         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 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);
-           break;
-         }
-      }
+       }
+    }
 }
 
 /* Create edges for a goto statement at block BB.  */
@@ -2147,7 +2157,8 @@ call_can_make_abnormal_goto (gimple t)
 {
   /* If the function has no non-local labels, then a call cannot make an
      abnormal transfer of control.  */
-  if (!cfun->has_nonlocal_label)
+  if (!cfun->has_nonlocal_label
+      && !cfun->calls_setjmp)
    return false;
 
   /* Likewise if the call has no side effects.  */
@@ -2302,6 +2313,11 @@ stmt_starts_bb_p (gimple stmt, gimple prev_stmt)
       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;
 }
@@ -7532,7 +7548,8 @@ gimple_purge_dead_abnormal_call_edges (basic_block bb)
   edge_iterator ei;
   gimple stmt = last_stmt (bb);
 
-  if (!cfun->has_nonlocal_label)
+  if (!cfun->has_nonlocal_label
+      && !cfun->calls_setjmp)
     return false;
 
   if (stmt && stmt_can_make_abnormal_goto (stmt))