The following prevents SLP CSE to create new cycles which happened
because of a 1:1 permute node being present where its child was then
CSEd to the permute node.  Fixed by making a node only available to
CSE to after recursing.

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

        PR tree-optimization/115602
        * tree-vect-slp.cc (vect_cse_slp_nodes): Delay populating the
        bst-map to avoid cycles.

        * gcc.dg/vect/pr114921.c: New testcase.
---
 gcc/testsuite/gcc.dg/vect/pr115602.c | 27 +++++++++++++++++++++++
 gcc/tree-vect-slp.cc                 | 33 ++++++++++++++++++----------
 2 files changed, 48 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/pr115602.c

diff --git a/gcc/testsuite/gcc.dg/vect/pr115602.c 
b/gcc/testsuite/gcc.dg/vect/pr115602.c
new file mode 100644
index 00000000000..9a208d1d950
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr115602.c
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+
+typedef struct {
+  double x, y;
+} pointf;
+struct {
+  pointf focus;
+  double zoom;
+  pointf devscale;
+  char button;
+  pointf oldpointer;
+} gvevent_motion_job;
+char gvevent_motion_job_4;
+double gvevent_motion_pointer_1, gvevent_motion_pointer_0;
+void gvevent_motion() {
+  double dx = (gvevent_motion_pointer_0 - gvevent_motion_job.oldpointer.x) /
+              gvevent_motion_job.devscale.x,
+         dy = (gvevent_motion_pointer_1 - gvevent_motion_job.oldpointer.y) /
+              gvevent_motion_job.devscale.y;
+  if (dx && dy < .0001)
+    return;
+  switch (gvevent_motion_job_4)
+  case 2: {
+    gvevent_motion_job.focus.x -= dy / gvevent_motion_job.zoom;
+    gvevent_motion_job.focus.y += dx / gvevent_motion_job.zoom;
+  }
+}
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 1d4f6089cfe..bb70a3fa5c2 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -6382,35 +6382,44 @@ vect_optimize_slp_pass::run ()
 static void
 vect_cse_slp_nodes (scalar_stmts_to_slp_tree_map_t *bst_map, slp_tree& node)
 {
+  bool put_p = false;
   if (SLP_TREE_DEF_TYPE (node) == vect_internal_def
       /* Besides some VEC_PERM_EXPR, two-operator nodes also
         lack scalar stmts and thus CSE doesn't work via bst_map.  Ideally
         we'd have sth that works for all internal and external nodes.  */
       && !SLP_TREE_SCALAR_STMTS (node).is_empty ())
     {
-      if (slp_tree *leader = bst_map->get (SLP_TREE_SCALAR_STMTS (node)))
+      slp_tree *leader = bst_map->get (SLP_TREE_SCALAR_STMTS (node));
+      if (leader)
        {
-         if (*leader != node)
-           {
-             if (dump_enabled_p ())
-               dump_printf_loc (MSG_NOTE, vect_location,
-                                "re-using SLP tree %p for %p\n",
-                                (void *)*leader, (void *)node);
-             vect_free_slp_tree (node);
-             (*leader)->refcnt += 1;
-             node = *leader;
-           }
+         /* We've visited this node already.  */
+         if (!*leader || *leader == node)
+           return;
+
+         if (dump_enabled_p ())
+           dump_printf_loc (MSG_NOTE, vect_location,
+                            "re-using SLP tree %p for %p\n",
+                            (void *)*leader, (void *)node);
+         vect_free_slp_tree (node);
+         (*leader)->refcnt += 1;
+         node = *leader;
          return;
        }
 
-      bst_map->put (SLP_TREE_SCALAR_STMTS (node).copy (), node);
+      /* Avoid creating a cycle by populating the map only after recursion.  */
+      bst_map->put (SLP_TREE_SCALAR_STMTS (node).copy (), nullptr);
       node->refcnt += 1;
+      put_p = true;
       /* And recurse.  */
     }
 
   for (slp_tree &child : SLP_TREE_CHILDREN (node))
     if (child)
       vect_cse_slp_nodes (bst_map, child);
+
+  /* Now record the node for CSE in other siblings.  */
+  if (put_p)
+    bst_map->put (SLP_TREE_SCALAR_STMTS (node).copy (), node);
 }
 
 /* Optimize the SLP graph of VINFO.  */
-- 
2.35.3

Reply via email to