[gcc r17-2654] Support two-lane vector BB reductions without target support
Richard Biener via Gcc-cvs <[email protected]>
| Newsgroups | gmane.comp.gcc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://gcc.gnu.org/g:fb0838bc1073aa5f22ec38e0cca2d70d625c6d71 commit r17-2654-gfb0838bc1073aa5f22ec38e0cca2d70d625c6d71 Author: Richard Biener <[email protected]> Date: Wed Jul 15 10:37:57 2026 +0200 Support two-lane vector BB reductions without target support 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. 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. Diff: --- gcc/testsuite/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(-) diff --git a/gcc/testsuite/c-c++-common/vector-subscript-4.c b/gcc/testsuite/c-c++-common/vector-subscript-4.c index 3138dc619d39..acd8bd19595d 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 69912a94cef0..437e54cadcb2 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 000000000000..18357be2df25 --- /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 9e9325f6c645..dcd35da43a29 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 @@ -12209,13 +12213,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;