tree-optimization/96163 - fix placement issue with SLP and vectors

This avoids placing stmts beyond the vectorizer region begin which
confuses vect_stmt_dominates_stmt_p.

2020-07-13  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/96163
	* tree-vect-slp.c (vect_schedule_slp_instance): Put new stmts
	at least after region begin.

	* g++.dg/vect/pr96163.cc: New testcase.
This commit is contained in:
Richard Biener 2020-07-13 12:41:35 +02:00
parent 3f06901101
commit c4facd483d
2 changed files with 166 additions and 12 deletions

View file

@ -0,0 +1,146 @@
// { dg-do compile }
// { dg-require-effective-target c++17 }
typedef double b __attribute__((__vector_size__(16)));
b c;
enum { d };
namespace e {
template <typename> struct g;
struct h {
enum { i, j };
};
template <typename> struct aa;
} // namespace e
template <typename> struct k;
template <typename> class l;
template <typename, int = e::h::j> class ab;
template <typename, int m, int n, int = 0, int = m, int = n> class o;
template <typename> class ac;
class p;
namespace e {
template <typename> struct q { typedef ac<o<double, 2, 1>> ae; };
struct s {
template <int, typename t> void af(double *ak, t) { *(b *)ak = c; }
};
} // namespace e
template <typename ad> class ab<ad, d> : public k<ad> {};
template <typename ad> class ab<ad> : public ab<ad, d> {
public:
typedef typename e::g<ad>::ag ag;
using ab<ad, d>::ah;
ag ai() {
long aj = 0;
return e::aa(ah()).ai(aj);
}
ag operator[](long) { return ai(); }
};
template <typename ad> class ay : public ab<ad> {
public:
enum { a, al };
};
template <typename ad> class ac : public ay<ad> {
public:
p am();
};
template <typename> struct k {
o<double, 2, 1> &ah() { return *static_cast<o<double, 2, 1> *>(this); }
};
namespace e {
template <typename f> struct aa { aa(f); };
template <typename ad> struct aa<l<ad>> {
typedef ad ao;
typedef typename ao::ag ag;
aa(ao &ak) : ap(ak.aq()) {}
ag &ai(long ak) { return ap[ak]; }
ag *ap;
};
template <typename ag, int ar, int as, int at, int au, int av>
struct aa<o<ag, ar, as, at, au, av>> : aa<l<o<ag, ar, as>>> {
typedef o<ag, ar, as> aw;
aa(aw &ak) : aa<l<aw>>(ak) {}
};
template <typename ax> struct u {
enum { az, ba, bb };
static void bc(ax ak) { ak.template be<bb, d, typename ax::bf>(az, ba); }
};
template <typename ax> struct v {
static void bc(ax ak) { u<ax>::bc(ak); }
};
template <typename bg, typename bh> class w {
typedef bg bi;
public:
typedef bg bj;
typedef bg bf;
w(bj ak, int, bh, bi x) : bk(ak), bl(x) {}
template <int bm, int, typename> void be(long, long) {
bn.template af<bm>(&bk.ai(0), 0);
}
bj bk;
bh bn;
bi bl;
};
template <typename bi, typename bo, typename bh> void bp(bi &ak, bo, bh bq) {
typedef aa<bi> bj;
bo br;
bj bs(ak);
typedef w<bj, bh> ax;
ax bd(bs, br, bq, ak);
v<ax>::bc(bd);
}
template <typename> struct bt;
template <typename bu, typename bv, typename bw> void bx(bu &ak, bv by, bw bq) {
bt<bw>::bc(ak, by, bq);
}
template <typename> struct bt {
static void bc(o<double, 2, 1> &ak, int by, s bq) { bp(ak, by, bq); }
};
} // namespace e
class bz {
public:
template <typename an> void operator*(an);
};
namespace e {
template <int ca> struct cb { double am[ca]; };
} // namespace e
template <int ca> class cc {
e::cb<ca> ap;
public:
double *aq() { return ap.am; }
};
template <typename ad> class l : public e::q<ad>::ae {
public:
typedef typename e::q<ad>::ae cd;
typedef typename e::g<ad>::ag ag;
cc<cd::al> ce;
ag *aq() { return ce.aq(); }
l() {}
template <typename an> l(an ak) { bx(this->ah(), ak, e::s()); }
template <typename cf, typename cg> void ch(cf, cg by) {
ag *z, *y;
{ z = aq(); }
y = z;
y[0] = aq()[1] = by;
}
};
namespace e {
template <typename ci, int m, int n, int cj, int ck, int cl>
struct g<o<ci, m, n, cj, ck, cl>> {
typedef ci ag;
};
} // namespace e
template <typename, int m, int n, int, int, int>
class o : public l<o<double, m, n>> {
public:
typedef l<o> cd;
template <typename cf, typename cg> o(cf ak, cg by) { cd::ch(ak, by); }
template <typename an> o(an ak) : cd(ak) {}
};
class p : public bz {};
double cq;
void cm() {
o<double, 2, 1> r = 0;
o cn = r;
cn.am() * o<double, 2, 1>(0, r[0] / cq).am();
}

View file

@ -4404,18 +4404,26 @@ vect_schedule_slp_instance (vec_info *vinfo,
else
{
/* For externals we have to look at all defs since their
insertion place is decided per vector. */
unsigned j;
tree vdef;
FOR_EACH_VEC_ELT (SLP_TREE_VEC_DEFS (child), j, vdef)
if (TREE_CODE (vdef) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (vdef))
{
gimple *vstmt = SSA_NAME_DEF_STMT (vdef);
if (!last_stmt
|| vect_stmt_dominates_stmt_p (last_stmt, vstmt))
last_stmt = vstmt;
}
insertion place is decided per vector. But beware
of pre-existing vectors where we need to make sure
we do not insert before the region boundary. */
if (SLP_TREE_SCALAR_OPS (child).is_empty ()
&& !vinfo->lookup_def (SLP_TREE_VEC_DEFS (child)[0]))
last_stmt = gsi_stmt (as_a <bb_vec_info> (vinfo)->region_begin);
else
{
unsigned j;
tree vdef;
FOR_EACH_VEC_ELT (SLP_TREE_VEC_DEFS (child), j, vdef)
if (TREE_CODE (vdef) == SSA_NAME
&& !SSA_NAME_IS_DEFAULT_DEF (vdef))
{
gimple *vstmt = SSA_NAME_DEF_STMT (vdef);
if (!last_stmt
|| vect_stmt_dominates_stmt_p (last_stmt, vstmt))
last_stmt = vstmt;
}
}
}
/* This can happen when all children are pre-existing vectors or
constants. */