When SLP analysis scraps an instance because it fails to analyze we can end up calling vectorizable_* in analysis mode on a node that was analyzed during the analysis of that instance again. vectorizable_simd_clone_call wasn't expecting that and instead guarded analysis/transform code on populated data structures. The following changes it so it survives re-analysis.
Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed. PR tree-optimization/116674 * tree-vect-stmts.cc (vectorizable_simd_clone_call): Support re-analysis. * g++.dg/vect/pr116674.cc: New testcase. --- gcc/testsuite/g++.dg/vect/pr116674.cc | 85 +++++++++++++++++++++++++++ gcc/tree-vect-stmts.cc | 8 ++- 2 files changed, 90 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/g++.dg/vect/pr116674.cc diff --git a/gcc/testsuite/g++.dg/vect/pr116674.cc b/gcc/testsuite/g++.dg/vect/pr116674.cc new file mode 100644 index 00000000000..1c13f12290b --- /dev/null +++ b/gcc/testsuite/g++.dg/vect/pr116674.cc @@ -0,0 +1,85 @@ +// { dg-do compile } +// { dg-require-effective-target c++11 } +// { dg-additional-options "-Ofast" } +// { dg-additional-options "-march=x86-64-v3" { target { x86_64-*-* i?86-*-* } } } + +namespace std { + typedef int a; + template <typename> struct b; + template <typename> class aa {}; + template <typename c> c d(c e, c) { return e; } + template <typename c> struct b<aa<c>> { + using f = c; + using g = c *; + template <typename h> using j = aa<h>; + }; +} // namespace std +namespace l { + template <typename ab> struct m : std::b<ab> { + typedef std::b<ab> n; + typedef typename n::f &q; + template <typename c> struct ac { typedef typename n::j<c> ad; }; + }; +} // namespace l +namespace std { + template <typename c, typename ab> struct o { + typedef typename l::m<ab>::ac<c>::ad ae; + typedef typename l::m<ae>::g g; + struct p { + g af; + }; + struct ag : p { + ag(ae) {} + }; + typedef ab u; + o(a, u e) : ah(e) {} + ag ah; + }; + template <typename c, typename ab = aa<c>> class r : o<c, ab> { + typedef o<c, ab> s; + typedef typename s::ae ae; + typedef l::m<ae> w; + + public: + c f; + typedef typename w::q q; + typedef a t; + typedef ab u; + r(t x, u e = u()) : s(ai(x, e), e) {} + q operator[](t x) { return *(this->ah.af + x); } + t ai(t x, u) { return x; } + }; + extern "C" __attribute__((__simd__)) double exp(double); +} // namespace std +using namespace std; +int ak; +double v, y; +void am(double, int an, double, double, double, double, double, double, double, + double, double, double, int, double, double, double, double, + r<double> ap, double, double, double, double, double, double, double, + double, r<double> ar, r<double> as, double, double, r<double> at, + r<double> au, r<double> av, double, double) { + double ba; + for (int k;;) + for (int i; i < an; ++i) { + y = i; + v = d(y, 25.0); + ba = exp(v); + ar[i * (ak + 1)] = ba; + as[i * (ak + 1)] = ar[i * (ak + 1)]; + if (k && ap[k]) { + at[i * (ak + 1)] = av[i * (ak + 1)] = as[i * (ak + 1)]; + au[i * (ak + 1)] = ar[i * (ak + 1)]; + } else { + au[i * (ak + 1)] = ba; + at[i * (ak + 1)] = av[i * (ak + 1)] = k; + } + } +} +void b(int bc) { + double bd, be, bf, bg, bh, ao, ap, bn, bo, bp, bq, br, bs, bt, bu, bv, bw, bx, + by, aq, ar, as, bz, ca, at, au, av, cb, aw; + int bi; + am(bh, bc, bi, bi, bi, bi, bv, bw, bx, by, bu, bt, bi, ao, bn, bo, bp, ap, bq, + br, bs, bd, be, bf, bg, aq, ar, as, bz, ca, at, au, av, cb, aw); +} diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc index 22d50263cdd..1d919ad2516 100644 --- a/gcc/tree-vect-stmts.cc +++ b/gcc/tree-vect-stmts.cc @@ -3987,6 +3987,8 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info, vec<tree>& simd_clone_info = (slp_node ? SLP_TREE_SIMD_CLONE_INFO (slp_node) : STMT_VINFO_SIMD_CLONE_INFO (stmt_info)); + if (!vec_stmt) + simd_clone_info.truncate (0); arginfo.reserve (nargs, true); auto_vec<slp_tree> slp_op; slp_op.safe_grow_cleared (nargs); @@ -4035,10 +4037,10 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info, /* For linear arguments, the analyze phase should have saved the base and step in {STMT_VINFO,SLP_TREE}_SIMD_CLONE_INFO. */ - if (i * 3 + 4 <= simd_clone_info.length () + if (vec_stmt + && i * 3 + 4 <= simd_clone_info.length () && simd_clone_info[i * 3 + 2]) { - gcc_assert (vec_stmt); thisarginfo.linear_step = tree_to_shwi (simd_clone_info[i * 3 + 2]); thisarginfo.op = simd_clone_info[i * 3 + 1]; thisarginfo.simd_lane_linear @@ -4093,7 +4095,7 @@ vectorizable_simd_clone_call (vec_info *vinfo, stmt_vec_info stmt_info, unsigned group_size = slp_node ? SLP_TREE_LANES (slp_node) : 1; unsigned int badness = 0; struct cgraph_node *bestn = NULL; - if (simd_clone_info.exists ()) + if (vec_stmt) bestn = cgraph_node::get (simd_clone_info[0]); else for (struct cgraph_node *n = node->simd_clones; n != NULL; -- 2.43.0