This is another aspect of the PR127693 showed missed FRE in loops
when there was a ref translation. When get_continuation_for_phi
is entered with abort_on_visited true because we're in the process
of walking a backedge with a translated ref it is important to
not call maybe_skip_until for the same virtual operand multiple
times as that will surely trip abort_on_visited. But that safety
is for detecting whether we already visited the place prior
to get_continuation_for_phi. The fix is to avoid doing duplicate
work (which is good in any case). Use a sorted vector of PHI
arguments for this.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.
PR tree-optimization/127693
* tree-ssa-alias.cc (cmp_intpair): New qsort helper.
(get_continuation_for_phi): Sort the PHI args and avoid
processing duplicates.
* gcc.dg/tree-ssa/ssa-fre-117.c: New testcase.
---
gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-117.c | 50 +++++++++++++++++++++
gcc/tree-ssa-alias.cc | 36 +++++++++++++--
2 files changed, 82 insertions(+), 4 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-117.c
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-117.c
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-117.c
new file mode 100644
index 00000000000..62bc1bddf28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-fre-117.c
@@ -0,0 +1,50 @@
+/* PR127693 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-fre3" } */
+
+typedef struct { long size; const short *data; } SV;
+typedef struct { SV given; } Scanner;
+long findString(SV h, long from, SV n);
+const short *strchr16(const short *b, const short *e, short c);
+
+static inline long findChar(SV h, long from, short c)
+{
+ if ((unsigned long)from < (unsigned long)h.size) {
+ const short *n = strchr16(h.data + from, h.data + h.size, c);
+ if (n != h.data + h.size)
+ return n - h.data;
+ }
+ return -1;
+}
+
+static inline long indexOf(const SV *h, SV n, long from)
+{
+ if (__builtin_constant_p(n.size) && n.size == 1)
+ return findChar(*h, from, n.data[0]);
+ return findString(*h, from, n);
+}
+
+static int scanForToken(Scanner *s, SV sought)
+{
+ long n = sought.size;
+ long idx = -n;
+ int count = 0;
+ while ((idx = indexOf(&s->given, sought, idx + n)) >= 0)
+ ++count;
+ return count;
+}
+
+__attribute__((noinline)) int scanForSigns(Scanner *s)
+{
+ static const short minus[] = { 0x2212 };
+ SV m = { 1, minus };
+ return scanForToken(s, m);
+}
+
+int f(SV h)
+{
+ Scanner s = { h };
+ return scanForSigns(&s);
+}
+
+/* { dg-final { scan-tree-dump-not "unreachable" "fre3" } } */
diff --git a/gcc/tree-ssa-alias.cc b/gcc/tree-ssa-alias.cc
index c1e5added30..de13ba3bcb6 100644
--- a/gcc/tree-ssa-alias.cc
+++ b/gcc/tree-ssa-alias.cc
@@ -3841,6 +3841,18 @@ maybe_skip_until (gimple *phi, tree &target, basic_block
target_bb,
return true;
}
+/* qsort comparator for a pair of int and bool. For same int sort
+ true before false. */
+
+static int
+cmp_intpair (const void *a_, const void *b_)
+{
+ auto a = (const std::pair<int, bool> *)a_;
+ auto b = (const std::pair<int, bool> *)b_;
+ if (a->first == b->first)
+ return (int)b->second - (int)a->second;
+ return a->first - b->first;
+}
/* Starting from a PHI node for the virtual operand of the memory reference
REF find a continuation virtual operand that allows to continue walking
@@ -3890,21 +3902,37 @@ get_continuation_for_phi (gphi *phi, ao_ref *ref, bool
tbaa_p,
do that for us. */
basic_block dom = get_immediate_dominator (CDI_DOMINATORS, phi_bb);
+ /* Sort the PHI arguments so we can quickly avoid walking duplicates.
+ Keep pairs of PHI arg and edge backedge state, sorting the backedge
+ case first which is the conservative walk kind in case we have
+ a duplicate PHI arg reachable both via a forward and a backward
+ edge. */
+ auto_vec<std::pair<int, bool>, 10> args;
+ for (i = 0; i < nargs; ++i)
+ args.safe_push (std::make_pair (SSA_NAME_VERSION (PHI_ARG_DEF (phi, i)),
+ (!is_backedge
+ || is_backedge
+ (gimple_phi_arg_edge (phi, i),
+ data))));
+ args.qsort (cmp_intpair);
+
/* Then check against the (to be) found candidate. */
for (i = 0; i < nargs; ++i)
{
- arg1 = PHI_ARG_DEF (phi, i);
+ arg1 = ssa_name (args[i].first);
if (arg1 == arg0)
;
+ else if (i > 0 && args[i].first == args[i-1].first)
+ /* Already visited paths can be skipped - we otherwise falsely
+ abort_on_visited. */
+ ;
else if (! maybe_skip_until (phi, arg0, dom, ref, arg1, tbaa_p,
limit, visited,
abort_on_visited,
translate, is_backedge,
/* Do not valueize when walking over
backedges. */
- (is_backedge
- && !is_backedge
- (gimple_phi_arg_edge (phi, i), data))
+ !args[i].second
? disambiguate_only : TR_DISAMBIGUATE,
data))
return NULL_TREE;
--
2.51.0