The following implements BB reduction epilog handling for two-lane
vectors with lane extracts.  This allows targets to omit defining
reduc_*_scal optabs for two lane vector modes and enables trivial
handling of in-order reductions with two lanes.  The former is
one issue we run into with PR126028 on x86_64.

This causes some no-op vectorization since we now accept vector
costs equal to scalar costs.

For gcc.target/i386/pr54400.c this shows that after SLP vectorizing
a two lane reduction we are no longer able to match up the x86 haddpd
instruction I have sent a partial x86 backend fix.
For g++.target/i386/pr114187.C it shows the usual
argument/return costing difficulties but also a too broad testcase
and inadverted coverage of -m32 - I have adjusted the testcase.

Bootstrapped and tested on x86_64-unknown-linux-gnu.  I'll push
this once the x86 prerequesite has landed.

Richard.

        PR tree-optimization/126028
        * tree-vect-slp.cc (vect_slp_check_for_roots): Move
        fold-left reduction check ...
        (vectorizable_bb_reduc_epilogue): ... here and allow
        two reduction lanes to be unaffected.  Handle the two
        vector lane without target support for the reduction.
        (vectorize_slp_instance_root_stmt): Implement manual two-lane
        reduction.

        * gcc.dg/vect/bb-slp-reduc-1.c: New testcase for a two-lane
        in-order reduction.
        * c-c++-common/vector-subscript-4.c: Use -fno-vectorize.
        * g++.target/i386/pr114187.C: Narrow pattern to better
        only catch the reported issue.
---
 .../c-c++-common/vector-subscript-4.c         |  2 +-
 gcc/testsuite/g++.target/i386/pr114187.C      |  3 +-
 gcc/testsuite/gcc.dg/vect/bb-slp-reduc-1.c    | 12 +++++
 gcc/tree-vect-slp.cc                          | 47 ++++++++++++++-----
 4 files changed, 49 insertions(+), 15 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/bb-slp-reduc-1.c

diff --git a/gcc/testsuite/c-c++-common/vector-subscript-4.c 
b/gcc/testsuite/c-c++-common/vector-subscript-4.c
index 3138dc619d3..acd8bd19595 100644
--- a/gcc/testsuite/c-c++-common/vector-subscript-4.c
+++ b/gcc/testsuite/c-c++-common/vector-subscript-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-nrv -w -Wno-psabi" } */
+/* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-nrv -w -Wno-psabi" } */
 
 #define foobar(n) \
     typedef int v##n##si __attribute__ ((vector_size (4 * n))); \
diff --git a/gcc/testsuite/g++.target/i386/pr114187.C 
b/gcc/testsuite/g++.target/i386/pr114187.C
index 69912a94cef..437e54cadcb 100644
--- a/gcc/testsuite/g++.target/i386/pr114187.C
+++ b/gcc/testsuite/g++.target/i386/pr114187.C
@@ -9,5 +9,6 @@ double sumxy_p(P2d p) {
     return p.x + p.y;
 }
 
-/* { dg-final { scan-assembler-not "movq" } } */
+/* No move between GPR and XMM.  */
+/* { dg-final { scan-assembler-not "movq\[ \t%\]*r" } } */
 /* { dg-final { scan-assembler-not "xchg" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/bb-slp-reduc-1.c 
b/gcc/testsuite/gcc.dg/vect/bb-slp-reduc-1.c
new file mode 100644
index 00000000000..18357be2df2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/bb-slp-reduc-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target vect_double } */
+
+double foo (double *x, double *y, double *z)
+{
+  return (x[0] * y[0] - z[0]) + (x[1] * y[1] - z[1]);
+}
+
+/* Even though without -ffast-math a reduction with double requires in-order
+   vectorization which we do not fully implement for BB vectorization we
+   should be able to handle the two-lane vector case just fine.  */
+/* { dg-final { scan-tree-dump "optimized: basic block part vectorized" "slp2" 
{ target vect_hw_misalign } } } */
diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
index 850cb1efacc..d1317fdde6e 100644
--- a/gcc/tree-vect-slp.cc
+++ b/gcc/tree-vect-slp.cc
@@ -9209,11 +9209,19 @@ vectorizable_bb_reduc_epilogue (slp_instance instance,
   internal_fn reduc_fn;
   tree vectype = SLP_TREE_VECTYPE (SLP_INSTANCE_TREE (instance));
   if (!vectype
-      || !reduction_fn_for_scalar_code (reduc_code, &reduc_fn)
-      || reduc_fn == IFN_LAST
-      || !direct_internal_fn_supported_p (reduc_fn, vectype, OPTIMIZE_FOR_BOTH)
       || !useless_type_conversion_p (TREE_TYPE (gimple_assign_lhs (stmt)),
-                                    TREE_TYPE (vectype)))
+                                    TREE_TYPE (vectype))
+      || (maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), 2u)
+         && (!reduction_fn_for_scalar_code (reduc_code, &reduc_fn)
+             || reduc_fn == IFN_LAST
+             || !direct_internal_fn_supported_p (reduc_fn, vectype,
+                                                 OPTIMIZE_FOR_BOTH)))
+      /* Two-element reductions do not need special-handling for fold-left,
+        other cases are not yet implemented.  remain_defs also have to
+        be included here.  */
+      || (needs_fold_left_reduction_p (TREE_TYPE (vectype), reduc_code)
+         && (!instance->remain_defs.is_empty ()
+             || maybe_ne (TYPE_VECTOR_SUBPARTS (vectype), 2u))))
     {
       if (dump_enabled_p ())
        dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
@@ -9996,10 +10004,6 @@ vect_slp_check_for_roots (bb_vec_info bb_vinfo)
        }
       else if (!VECTOR_TYPE_P (TREE_TYPE (rhs))
               && (associative_tree_code (code) || code == MINUS_EXPR)
-              /* ???  This pessimizes a two-element reduction.  PR54400.
-                 ???  In-order reduction could be handled if we only
-                 traverse one operand chain in vect_slp_linearize_chain.  */
-              && !needs_fold_left_reduction_p (TREE_TYPE (rhs), code)
               /* Ops with constants at the tail can be stripped here.  */
               && TREE_CODE (rhs) == SSA_NAME
               && TREE_CODE (gimple_assign_rhs2 (assign)) == SSA_NAME
@@ -12215,13 +12219,30 @@ vectorize_slp_instance_root_stmt (vec_info *vinfo, 
slp_tree node, slp_instance i
                                  vec_def, def);
        }
       vec_defs.release ();
-      /* ???  Support other schemes than direct internal fn.  */
+      /* ???  Support other schemes than direct internal fn or two
+        element vectors.  */
+      tree scalar_def;
       internal_fn reduc_fn;
       if (!reduction_fn_for_scalar_code (reduc_code, &reduc_fn)
-         || reduc_fn == IFN_LAST)
-       gcc_unreachable ();
-      tree scalar_def = gimple_build (&epilogue, as_combined_fn (reduc_fn),
-                                     TREE_TYPE (compute_vectype), vec_def);
+         || reduc_fn == IFN_LAST
+         || !direct_internal_fn_supported_p (reduc_fn, compute_vectype,
+                                             OPTIMIZE_FOR_BOTH))
+       {
+         gcc_assert (known_eq (TYPE_VECTOR_SUBPARTS (compute_vectype), 2u));
+         tree tem0 = gimple_build (&epilogue, BIT_FIELD_REF,
+                                   TREE_TYPE (compute_vectype), vec_def,
+                                   TYPE_SIZE (TREE_TYPE (compute_vectype)),
+                                   bitsize_zero_node);
+         tree tem1 = gimple_build (&epilogue, BIT_FIELD_REF,
+                                   TREE_TYPE (compute_vectype), vec_def,
+                                   TYPE_SIZE (TREE_TYPE (compute_vectype)),
+                                   TYPE_SIZE (TREE_TYPE (compute_vectype)));
+         scalar_def = gimple_build (&epilogue, reduc_code,
+                                    TREE_TYPE (compute_vectype), tem0, tem1);
+       }
+      else
+       scalar_def = gimple_build (&epilogue, as_combined_fn (reduc_fn),
+                                  TREE_TYPE (compute_vectype), vec_def);
       if (!SLP_INSTANCE_REMAIN_DEFS (instance).is_empty ())
        {
          tree rem_def = NULL_TREE;
-- 
2.51.0

Reply via email to