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:
parent
3f06901101
commit
c4facd483d
2 changed files with 166 additions and 12 deletions
146
gcc/testsuite/g++.dg/vect/pr96163.cc
Normal file
146
gcc/testsuite/g++.dg/vect/pr96163.cc
Normal 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();
|
||||
}
|
|
@ -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. */
|
||||
|
|
Loading…
Add table
Reference in a new issue