mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-21 00:21:03 +08:00
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:
parent
7de23b8c53
commit
c0bfd9672e
83
gcc/testsuite/g++.dg/vect/slp-pr97636.cc
Normal file
83
gcc/testsuite/g++.dg/vect/slp-pr97636.cc
Normal 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);
|
||||
}
|
27
gcc/testsuite/gcc.dg/vect/bb-slp-pr97633.c
Normal file
27
gcc/testsuite/gcc.dg/vect/bb-slp-pr97633.c
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user