tree-optimization/97633 - fix SLP scheduling of single-node cycles

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.
This commit is contained in:
Richard Biener 2020-10-30 09:57:02 +01:00
parent 7de23b8c53
commit c0bfd9672e
3 changed files with 198 additions and 74 deletions

View File

@ -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);
}

View File

@ -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;
}
}
}

View 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. */