tree-optimization/97633 - fix SLP scheduling of single-node cycles
authorRichard Biener <rguenther@suse.de>
Fri, 30 Oct 2020 08:57:02 +0000 (09:57 +0100)
committerRichard Biener <rguenther@suse.de>
Fri, 30 Oct 2020 09:46:08 +0000 (10:46 +0100)
This makes sure to update backedges in single-node cycles.

2020-10-30  Richard Biener  <rguenther@suse.de>

PR tree-optimization/97633
* tree-vect-slp.c (): Update backedges in single-node cycles.
Optimize processing of externals.

* g++.dg/vect/slp-pr97636.cc: New testcase.
* gcc.dg/vect/bb-slp-pr97633.c: Likewise.

gcc/testsuite/g++.dg/vect/slp-pr97636.cc [new file with mode: 0644]
gcc/testsuite/gcc.dg/vect/bb-slp-pr97633.c [new file with mode: 0644]
gcc/tree-vect-slp.c

diff --git a/gcc/testsuite/g++.dg/vect/slp-pr97636.cc b/gcc/testsuite/g++.dg/vect/slp-pr97636.cc
new file mode 100644 (file)
index 0000000..0123420
--- /dev/null
@@ -0,0 +1,83 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target c++17 } */
+
+struct u {
+  int b;
+  int c;
+  template <typename d, typename e> u(d, e);
+};
+template <class, class> struct f { u g; };
+template <class h, class i> class v {
+  typedef f<h, i> k;
+  k *l[4];
+  k m;
+public:
+  v(h, h);
+  void aa(h, i);
+};
+template <class h, class i> void v<h, i>::aa(h, i) { n(&l[1], &m); }
+template <class h, class i> void n(f<h, i> **o, f<h, i> *ab) {
+  bool p, r;
+  f q = **o;
+  f<h, i> *t;
+  h a = q.g;
+  h b = t->g;
+  if (r)
+    ;
+  else
+    goto ac;
+s:
+  p = a.b || a.c < b.c;
+  if (p)
+    goto s;
+ac:
+  ab->g = b;
+  b = t->g;
+  goto s;
+}
+template <class, class, class> class w {};
+template <class> class x;
+template <class, class> class z;
+class ad {
+public:
+  template <typename, typename y, typename ae, typename af, typename ag>
+  static void ah(const z<y, ae> &, const z<y, af> &, x<ag> *&);
+};
+template <typename, typename y, typename ae, typename af, typename ag>
+void ad::ah(const z<y, ae> &ai, const z<y, af> &aj, x<ag> *&) {
+  u c(0, 0), d(0, 0), g(aj, ai);
+  v<u, y> e(c, d);
+  e.aa(g, 0);
+}
+template <class, class> class ak;
+template <class, class, class al, class am, class an>
+void ao(ak<al, am> ap, ak<al, an> aq) {
+  x<double> *f;
+  ad::ah<int>(*ap.ar, *aq.ar, f);
+}
+template <typename, typename, typename al, typename am, typename an,
+          typename as, typename at>
+void au(w<al, am, as> ap, w<al, an, at> aq) {
+  ao<int, double>(static_cast<as &>(ap), static_cast<at &>(aq));
+}
+template <class, class> class z {};
+template <class, class> class ak : public w<int, int, ak<int, int>> {
+public:
+  z<int, int> *ar;
+};
+template <class, class, class> class av;
+template <typename, typename, typename, typename al, typename am, typename an,
+          typename aw, typename ax>
+void ay(av<al, am, aw>, av<al, an, ax>) {
+  aw h, i;
+  au<int, double>(h, i);
+}
+template <class, class, class> class av {};
+class az {
+public:
+  typedef av<int, double, ak<int, double>> ba;
+};
+int main() {
+  az::ba j, k;
+  ay<int, double, az>(j, k);
+}
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-pr97633.c b/gcc/testsuite/gcc.dg/vect/bb-slp-pr97633.c
new file mode 100644 (file)
index 0000000..ab0ae1d
--- /dev/null
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+
+extern short i (void);
+
+struct {
+  short a;
+  short b;
+} c;
+
+int d, e;
+static int f = 1;
+
+void g () {
+  if (e) {
+    if (f)
+      goto L;
+    while (d) {
+      i ();
+      short j = d, k = i (), l = k;
+    L:
+      if (!(d && e) || l)
+        goto L;
+      c.a = j;
+      c.b = k;
+    }
+  }
+}
index 5d69a98c2a90be47ff852c90039b0ab2cd2e58ef..714e50697bd5c6f3104710794fa33cf3703c9011 100644 (file)
@@ -5554,97 +5554,114 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
   gcc_assert (!existed_p);
   info->dfs = maxdfs;
   info->lowlink = maxdfs;
-  info->on_stack = true;
   maxdfs++;
+
+  /* Leaf.  */
+  if (SLP_TREE_DEF_TYPE (node) != vect_internal_def)
+    {
+      info->on_stack = false;
+      vect_schedule_slp_node (vinfo, node, instance);
+      return;
+    }
+
+  info->on_stack = true;
   stack.safe_push (node);
+
   unsigned i;
   slp_tree child;
-
-  /* ???  We're keeping SLP_TREE_CHILDREN of externalized nodes.  */
-  if (SLP_TREE_DEF_TYPE (node) == vect_internal_def)
-    FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
-      {
-       if (!child)
-         continue;
-       slp_scc_info *child_info = scc_info.get (child);
-       if (!child_info)
-         {
-           vect_schedule_scc (vinfo, child, instance, scc_info, maxdfs, stack);
-           /* Recursion might have re-allocated the node.  */
-           info = scc_info.get (node);
-           child_info = scc_info.get (child);
-           info->lowlink = MIN (info->lowlink, child_info->lowlink);
-         }
-       else if (child_info->on_stack)
-         info->lowlink = MIN (info->lowlink, child_info->dfs);
-      }
+  /* DFS recurse.  */
+  FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (node), i, child)
+    {
+      if (!child)
+       continue;
+      slp_scc_info *child_info = scc_info.get (child);
+      if (!child_info)
+       {
+         vect_schedule_scc (vinfo, child, instance, scc_info, maxdfs, stack);
+         /* Recursion might have re-allocated the node.  */
+         info = scc_info.get (node);
+         child_info = scc_info.get (child);
+         info->lowlink = MIN (info->lowlink, child_info->lowlink);
+       }
+      else if (child_info->on_stack)
+       info->lowlink = MIN (info->lowlink, child_info->dfs);
+    }
   if (info->lowlink != info->dfs)
     return;
 
+  auto_vec<slp_tree, 4> phis_to_fixup;
+
   /* Singleton.  */
   if (stack.last () == node)
     {
       stack.pop ();
       info->on_stack = false;
       vect_schedule_slp_node (vinfo, node, instance);
-      return;
+      if (SLP_TREE_CODE (node) != VEC_PERM_EXPR
+         && is_a <gphi *> (SLP_TREE_REPRESENTATIVE (node)->stmt))
+       phis_to_fixup.quick_push (node);
     }
-  /* SCC.  */
-  int last_idx = stack.length () - 1;
-  while (stack[last_idx] != node)
-    last_idx--;
-  /* We can break the cycle at PHIs who have at least one child
-     code generated.  Then we could re-start the DFS walk until
-     all nodes in the SCC are covered (we might have new entries
-     for only back-reachable nodes).  But it's simpler to just
-     iterate and schedule those that are ready.  */
-  auto_vec<slp_tree, 4> phis_to_fixup;
-  unsigned todo = stack.length () - last_idx;
-  do
+  else
     {
-      for (int idx = stack.length () - 1; idx >= last_idx; --idx)
+      /* SCC.  */
+      int last_idx = stack.length () - 1;
+      while (stack[last_idx] != node)
+       last_idx--;
+      /* We can break the cycle at PHIs who have at least one child
+        code generated.  Then we could re-start the DFS walk until
+        all nodes in the SCC are covered (we might have new entries
+        for only back-reachable nodes).  But it's simpler to just
+        iterate and schedule those that are ready.  */
+      unsigned todo = stack.length () - last_idx;
+      do
        {
-         slp_tree entry = stack[idx];
-         if (!entry)
-           continue;
-         bool phi = (SLP_TREE_CODE (entry) != VEC_PERM_EXPR
-                     && is_a <gphi *> (SLP_TREE_REPRESENTATIVE (entry)->stmt));
-         bool ready = !phi;
-         FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (entry), i, child)
-           if (!child)
-             {
-               gcc_assert (phi);
-               ready = true;
-               break;
-             }
-           else if (scc_info.get (child)->on_stack)
-             {
-               if (!phi)
-                 {
-                   ready = false;
-                   break;
-                 }
-             }
-           else
-             {
-               if (phi)
-                 {
-                   ready = true;
-                   break;
-                 }
-             }
-         if (ready)
+         for (int idx = stack.length () - 1; idx >= last_idx; --idx)
            {
-             vect_schedule_slp_node (vinfo, entry, instance);
-             scc_info.get (entry)->on_stack = false;
-             stack[idx] = NULL;
-             todo--;
-             if (phi)
-               phis_to_fixup.safe_push (entry);
+             slp_tree entry = stack[idx];
+             if (!entry)
+               continue;
+             bool phi = (SLP_TREE_CODE (entry) != VEC_PERM_EXPR
+                         && is_a <gphi *> (SLP_TREE_REPRESENTATIVE (entry)->stmt));
+             bool ready = !phi;
+             FOR_EACH_VEC_ELT (SLP_TREE_CHILDREN (entry), i, child)
+                 if (!child)
+                   {
+                     gcc_assert (phi);
+                     ready = true;
+                     break;
+                   }
+                 else if (scc_info.get (child)->on_stack)
+                   {
+                     if (!phi)
+                       {
+                         ready = false;
+                         break;
+                       }
+                   }
+                 else
+                   {
+                     if (phi)
+                       {
+                         ready = true;
+                         break;
+                       }
+                   }
+             if (ready)
+               {
+                 vect_schedule_slp_node (vinfo, entry, instance);
+                 scc_info.get (entry)->on_stack = false;
+                 stack[idx] = NULL;
+                 todo--;
+                 if (phi)
+                   phis_to_fixup.safe_push (entry);
+               }
            }
        }
+      while (todo != 0);
+
+      /* Pop the SCC.  */
+      stack.truncate (last_idx);
     }
-  while (todo != 0);
 
   /* Now fixup the backedge def of the vectorized PHIs in this SCC.  */
   slp_tree phi_node;
@@ -5666,9 +5683,6 @@ vect_schedule_scc (vec_info *vinfo, slp_tree node, slp_instance instance,
                         e, gimple_phi_arg_location (phi, dest_idx));
        }
     }
-
-  /* Pop the SCC.  */
-  stack.truncate (last_idx);
 }
 
 /* Generate vector code for SLP_INSTANCES in the loop/basic block.  */