The following addresses a missed optimization caused by the PR54498
correctness fix.  For CFG cycles when get_continuation_for_phi
is invoked on a loop PHI with a backedge and abort_on_visited true
because we have translated the reference maybe_skip_until will fail
because we will definitely hit that PHI again.  But the intent was to
catch re-visiting actual statements which we will do eventually by
visiting the other PHI edges from the caller.  So finish the walk
at the original PHI latest.

This allows the constant 1 to be propagated to the __builtin_constant_p
and the bug avoided.

Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

        PR tree-optimization/127693
        * tree-ssa-alias.cc (maybe_skip_until): Stop when reaching
        the PHI again.

        * gcc.dg/tree-ssa/ssa-fre-116.c: New testcase.
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-116.c | 47 +++++++++++++++++++++
 gcc/tree-ssa-alias.cc                       |  8 +++-
 2 files changed, 53 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-116.c

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-116.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-116.c
new file mode 100644
index 00000000000..7f022a3da36
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-116.c
@@ -0,0 +1,47 @@
+/* PR127693 */
+/* { dg-do run } */
+/* { dg-options "-O2 -fdump-tree-fre3" } */
+
+struct SV { long m_size; };
+
+__attribute__((noipa))
+long findString(long from, struct SV needle)
+{
+  __builtin_abort ();
+}
+
+__attribute__((noipa))
+long findChar(long from)
+{
+  if (from == 0)
+    return 1;
+  return -1;
+}
+
+static long indexOf(struct SV s, long from)
+{
+  if (__builtin_constant_p(s.m_size) && s.m_size == 1)
+    return findChar(from);
+  return findString(from, s);
+}
+
+static int scan(struct SV sought)
+{
+  long n = sought.m_size;
+  long idx = -n;
+  int matched = 0;
+  while ((idx = indexOf(sought, idx + n)) >= 0)
+    ++matched;
+  return matched;
+}
+
+int f(void) { return scan((struct SV){1}); }
+
+int main()
+{
+  if (f() != 1)
+    __builtin_abort ();
+  return 0;
+}
+
+/* { dg-final { scan-tree-dump-not "unreachable" "fre3" } } */
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index 7fc87b3b944..c1e5added30 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -3792,8 +3792,12 @@ maybe_skip_until (gimple *phi, tree &target, basic_block 
target_bb,
          return true;
        }
 
-      /* Recurse for PHI nodes.  */
-      if (gphi *phi = dyn_cast <gphi *> (def_stmt))
+      /* When we reach the original PHI we are done.  TARGET must be
+        reached via other edges in the caller.  */
+      if (def_stmt == phi)
+       return true;
+      /* Recurse for other PHI nodes.  */
+      else if (gphi *phi = dyn_cast <gphi *> (def_stmt))
        {
          /* An already visited PHI node ends the walk successfully.  */
          if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (phi))))
-- 
2.51.0

Reply via email to