This makes us avoid PREing calls that could trap across other
calls that might not return.  The PR88087 testcase has exactly
such case so I've refactored the testcase to contain a valid PRE.
I've also adjusted PRE to not consider pure calls possibly
not returning in line with what we do elsewhere.

Note we don't have a good idea whether a function always returns
normally or whether its body is known to never trap.  That's
something IPA could compute.

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

2021-09-01  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/93491
        * tree-ssa-pre.c (compute_avail): Set BB_MAY_NOTRETURN
        after processing the stmt itself.  Do not consider
        pure functions possibly not returning.  Properly avoid
        adding possibly trapping calls to EXP_GEN when there's
        a preceeding possibly not returning call.
        * tree-ssa-sccvn.c (vn_reference_may_trap): Conservatively
        not handle calls.

        * gcc.dg/torture/pr93491.c: New testcase.
        * gcc.dg/tree-ssa/pr88087.c: Change to valid PRE opportunity.
---
 gcc/testsuite/gcc.dg/torture/pr93491.c  | 24 ++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/pr88087.c | 18 +++++++-------
 gcc/tree-ssa-pre.c                      | 33 +++++++++++++++++++------
 gcc/tree-ssa-sccvn.c                    |  1 +
 4 files changed, 60 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr93491.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr93491.c 
b/gcc/testsuite/gcc.dg/torture/pr93491.c
new file mode 100644
index 00000000000..2cb4c0ca7af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr93491.c
@@ -0,0 +1,24 @@
+/* { dg-do run } */
+
+extern void exit (int);
+
+__attribute__((noipa))
+void f(int i)
+{
+  exit(i);
+}
+
+__attribute__((const,noipa))
+int g(int i)
+{
+  return 1 / i;
+}
+
+int main()
+{
+  while (1)
+    {
+      f(0);
+      f(g(0));
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c 
b/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c
index d0061b61aed..c48dba5bf21 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr88087.c
@@ -1,17 +1,17 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-pre-stats" } */
+/* { dg-options "-O2 -fno-code-hoisting -fdump-tree-pre-stats" } */
 
 int f();
 int d;
-void c()
+void c(int x)
 {
-  for (;;)
-    {
-      f();
-      int (*fp)() __attribute__((const)) = (void *)f;
-      d = fp();
-    }
+  int (*fp)() __attribute__((const)) = (void *)f;
+  if (x)
+    d = fp ();
+  int tem = fp ();
+  f();
+  d = tem;
 }
 
-/* We shouldn't ICE and hoist the const call of fp out of the loop.  */
+/* We shouldn't ICE and PRE the const call.  */
 /* { dg-final { scan-tree-dump "Eliminated: 1" "pre" } } */
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index ebe95cc6c73..769aadb2315 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -3957,6 +3957,7 @@ compute_avail (function *fun)
 
       /* Now compute value numbers and populate value sets with all
         the expressions computed in BLOCK.  */
+      bool set_bb_may_notreturn = false;
       for (gimple_stmt_iterator gsi = gsi_start_bb (block); !gsi_end_p (gsi);
           gsi_next (&gsi))
        {
@@ -3965,6 +3966,12 @@ compute_avail (function *fun)
 
          stmt = gsi_stmt (gsi);
 
+         if (set_bb_may_notreturn)
+           {
+             BB_MAY_NOTRETURN (block) = 1;
+             set_bb_may_notreturn = false;
+           }
+
          /* Cache whether the basic-block has any non-visible side-effect
             or control flow.
             If this isn't a call or it is the last stmt in the
@@ -3976,10 +3983,12 @@ compute_avail (function *fun)
                 that forbids hoisting possibly trapping expressions
                 before it.  */
              int flags = gimple_call_flags (stmt);
-             if (!(flags & ECF_CONST)
+             if (!(flags & (ECF_CONST|ECF_PURE))
                  || (flags & ECF_LOOPING_CONST_OR_PURE)
                  || stmt_can_throw_external (fun, stmt))
-               BB_MAY_NOTRETURN (block) = 1;
+               /* Defer setting of BB_MAY_NOTRETURN to avoid it
+                  influencing the processing of the call itself.  */
+               set_bb_may_notreturn = true;
            }
 
          FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
@@ -4030,11 +4039,16 @@ compute_avail (function *fun)
                /* If the value of the call is not invalidated in
                   this block until it is computed, add the expression
                   to EXP_GEN.  */
-               if (!gimple_vuse (stmt)
-                   || gimple_code
-                        (SSA_NAME_DEF_STMT (gimple_vuse (stmt))) == GIMPLE_PHI
-                   || gimple_bb (SSA_NAME_DEF_STMT
-                                   (gimple_vuse (stmt))) != block)
+               if ((!gimple_vuse (stmt)
+                    || gimple_code
+                         (SSA_NAME_DEF_STMT (gimple_vuse (stmt))) == GIMPLE_PHI
+                    || gimple_bb (SSA_NAME_DEF_STMT
+                                  (gimple_vuse (stmt))) != block)
+                   /* If the REFERENCE traps and there was a preceding
+                      point in the block that might not return avoid
+                      adding the reference to EXP_GEN.  */
+                   && (!BB_MAY_NOTRETURN (block)
+                       || !vn_reference_may_trap (ref)))
                  {
                    result = get_or_alloc_expr_for_reference
                               (ref, gimple_location (stmt));
@@ -4220,6 +4234,11 @@ compute_avail (function *fun)
              break;
            }
        }
+      if (set_bb_may_notreturn)
+       {
+         BB_MAY_NOTRETURN (block) = 1;
+         set_bb_may_notreturn = false;
+       }
 
       if (dump_file && (dump_flags & TDF_DETAILS))
        {
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index bf87cee3857..2357bbdbf90 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -5851,6 +5851,7 @@ vn_reference_may_trap (vn_reference_t ref)
     case MODIFY_EXPR:
     case CALL_EXPR:
       /* We do not handle calls.  */
+      return true;
     case ADDR_EXPR:
       /* And toplevel address computations never trap.  */
       return false;
-- 
2.31.1

Reply via email to