Hi!

As described in the PR, __builtin_setjmp_receiver isn't declared to
returns_twice, and thus after dce cfun->calls_setjmp might be no longer true.
At RTL __builtin_setjmp_receiver is handled as non-local label, so this
patch just forces cfun->has_nonlocal_label already in GIMPLE, so that
e.g. the inliner still sees stmt_can_make_nonlocal_goto.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2014-01-31  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/60003
        * gimple-low.c (lower_builtin_setjmp): Set cfun->has_nonlocal_label.
        * profile.c (branch_prob): Use gimple_call_builtin_p
        to check for BUILT_IN_SETJMP_RECEIVER.
        * tree-inline.c (copy_bb): Call notice_special_calls.

        * gcc.c-torture/execute/pr60003.c: New test.

--- gcc/gimple-low.c.jj 2014-01-29 12:43:25.000000000 +0100
+++ gcc/gimple-low.c    2014-01-31 10:02:38.843026680 +0100
@@ -709,6 +709,12 @@ lower_builtin_setjmp (gimple_stmt_iterat
   tree dest, t, arg;
   gimple g;

+  /* __builtin_setjmp_{setup,receiver} aren't ECF_RETURNS_TWICE and for RTL
+     these builtins are modelled as non-local label jumps to the label
+     that is passed to these two builtins, so pretend we have a non-local
+     label during GIMPLE passes too.  See PR60003.  */ 
+  cfun->has_nonlocal_label = true;
+
   /* NEXT_LABEL is the label __builtin_longjmp will jump to.  Its address is
      passed to both __builtin_setjmp_setup and __builtin_setjmp_receiver.  */
   FORCED_LABEL (next_label) = 1;
--- gcc/profile.c.jj    2014-01-29 12:43:25.000000000 +0100
+++ gcc/profile.c       2014-01-31 10:18:00.450198256 +0100
@@ -1104,7 +1104,6 @@ branch_prob (void)
            {
              gimple_stmt_iterator gsi;
              gimple first;
-             tree fndecl;
 
              gsi = gsi_start_nondebug_after_labels_bb (bb);
              gcc_checking_assert (!gsi_end_p (gsi));
@@ -1114,10 +1113,7 @@ branch_prob (void)
                 special and don't expect anything to be inserted before
                 them.  */
              if (is_gimple_call (first)
-                 && (((fndecl = gimple_call_fndecl (first)) != NULL
-                      && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
-                      && (DECL_FUNCTION_CODE (fndecl)
-                          == BUILT_IN_SETJMP_RECEIVER))
+                 && (gimple_call_builtin_p (first, BUILT_IN_SETJMP_RECEIVER)
                      || (gimple_call_flags (first) & ECF_RETURNS_TWICE)
                      || (gimple_call_internal_p (first)
                          && (gimple_call_internal_fn (first)
--- gcc/tree-inline.c.jj        2014-01-29 12:43:24.000000000 +0100
+++ gcc/tree-inline.c   2014-01-31 10:19:13.849815593 +0100
@@ -1745,7 +1745,6 @@ copy_bb (copy_body_data *id, basic_block
          if (is_gimple_call (stmt))
            {
              struct cgraph_edge *edge;
-             int flags;
 
              switch (id->transform_call_graph_edges)
                {
@@ -1868,11 +1867,7 @@ copy_bb (copy_body_data *id, basic_block
                    }
                }
 
-             flags = gimple_call_flags (stmt);
-             if (flags & ECF_MAY_BE_ALLOCA)
-               cfun->calls_alloca = true;
-             if (flags & ECF_RETURNS_TWICE)
-               cfun->calls_setjmp = true;
+             notice_special_calls (stmt);
            }
 
          maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt,
--- gcc/testsuite/gcc.c-torture/execute/pr60003.c.jj    2014-01-31 
10:05:15.095205547 +0100
+++ gcc/testsuite/gcc.c-torture/execute/pr60003.c       2014-01-31 
10:04:59.000000000 +0100
@@ -0,0 +1,48 @@
+/* PR tree-optimization/60003 */
+
+extern void abort (void);
+
+unsigned long long jmp_buf[5];
+
+__attribute__((noinline, noclone)) void
+baz (void)
+{
+  __builtin_longjmp (&jmp_buf, 1);
+}
+
+void
+bar (void)
+{
+  baz ();
+}
+
+__attribute__((noinline, noclone)) int
+foo (int x)
+{
+  int a = 0;
+
+  if (__builtin_setjmp (&jmp_buf) == 0)
+    {
+      while (1)
+       {
+         a = 1;
+         bar ();  /* OK if baz () instead */
+       }
+    }
+  else
+    {
+      if (a == 0)
+       return 0;
+      else
+       return x;
+    }
+}
+
+int
+main ()
+{
+  if (foo (1) == 0)
+    abort ();
+
+  return 0;
+}

        Jakub

Reply via email to