The following adds vec_decostruct to replace nunits * vec_to_scalar
which allows for more precise costing whenever vectorization
needs to decompose a vector to pieces, like for emulated gather/scatter
but also for strided [SLP] loads/stores.

This requires changes across targets, both for the different kind
but also for the difference in expected count.  For now this adjusts
them all to handle vec_deconstruct like vec_construct to avoid ICEing.

Bootstrapped/tested on x86_64-unknown-linux-gnu and pushed.

So I got yelled at from the pre-checkin CI for not handling for
arm and aarch64 which will the ICE in their builtin_vectorization_cost
hook.  So will all other targets.  Meaning I have amended this patch
by handling of vec_deconstruct like vec_construct for _all_ targets.
It's of a similar ballpark cost so not too obviously wrong.  You
still might want to double-check explicit matching on vec_to_scalar
for parts of gather/scatter or strided load/store pattern matching
in your add_stmt costing hook (if you have that).

Richard.

        * target.h (vect_cost_for_stmt::vec_deconstruct): New kind.
        * tree-vect-loop.cc (vect_model_reduction_cost): Use it.
        * tree-vect-stmts.cc (vectorizable_store): Likewise.
        (vectorizable_load): Likewise.
        * tree-vectorizer.cc (dump_stmt_cost): Handle vec_deconstruct.
        * config/aarch64/aarch64.cc (aarch64_builtin_vectorization_cost):
        Handle vec_deconstruct like vec_construct.
        * config/i386/i386.cc (ix86_default_vector_cost): Likewise.
        * config/arm/arm.cc (arm_builtin_vectorization_cost): Likewise.
        * config/loongarch/loongarch.cc (loongarch_builtin_vectorization_cost):
        Likewise.
        * config/riscv/riscv.cc (riscv_builtin_vectorization_cost):
        Likewise.
        * config/rs6000/rs6000.cc (rs6000_builtin_vectorization_cost):
        Likewise.
        * config/s390/s390.cc (s390_builtin_vectorization_cost): Likewise.
        * targhooks.cc (default_builtin_vectorization_cost): Likewise.
---
 gcc/config/aarch64/aarch64.cc     |  1 +
 gcc/config/arm/arm.cc             |  1 +
 gcc/config/i386/i386.cc           |  1 +
 gcc/config/loongarch/loongarch.cc |  1 +
 gcc/config/riscv/riscv.cc         |  1 +
 gcc/config/rs6000/rs6000.cc       |  1 +
 gcc/config/s390/s390.cc           |  1 +
 gcc/target.h                      |  3 ++-
 gcc/targhooks.cc                  |  1 +
 gcc/tree-vect-loop.cc             | 11 +++++------
 gcc/tree-vect-stmts.cc            | 15 +++++++--------
 gcc/tree-vectorizer.cc            |  3 +++
 12 files changed, 25 insertions(+), 15 deletions(-)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 42e56512c61..c9403ed94e7 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -17766,6 +17766,7 @@ aarch64_builtin_vectorization_cost (enum 
vect_cost_for_stmt type_of_cost,
                  : simd_costs->int_stmt_cost;
 
       case vec_construct:
+      case vec_deconstruct:
        elements = estimated_poly_value (TYPE_VECTOR_SUBPARTS (vectype));
        return elements / 2 + 1;
 
diff --git a/gcc/config/arm/arm.cc b/gcc/config/arm/arm.cc
index d24b06a6445..0bc66abe238 100644
--- a/gcc/config/arm/arm.cc
+++ b/gcc/config/arm/arm.cc
@@ -12732,6 +12732,7 @@ arm_builtin_vectorization_cost (enum vect_cost_for_stmt 
type_of_cost,
         return current_tune->vec_costs->vec_stmt_cost;
 
       case vec_construct:
+      case vec_deconstruct:
        elements = TYPE_VECTOR_SUBPARTS (vectype);
        return elements / 2 + 1;
 
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index b1fd86c2b32..1734996c68a 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -25699,6 +25699,7 @@ ix86_default_vector_cost (enum vect_cost_for_stmt 
type_of_cost,
         return ix86_vec_cost (mode, ix86_cost->sse_op);
 
       case vec_construct:
+      case vec_deconstruct:
        {
          int n = GET_MODE_NUNITS (mode);
          /* N - 1 element inserts into an SSE vector, the possible
diff --git a/gcc/config/loongarch/loongarch.cc 
b/gcc/config/loongarch/loongarch.cc
index 40111971501..131f7b3f57b 100644
--- a/gcc/config/loongarch/loongarch.cc
+++ b/gcc/config/loongarch/loongarch.cc
@@ -4547,6 +4547,7 @@ loongarch_builtin_vectorization_cost (enum 
vect_cost_for_stmt type_of_cost,
        return 2;
 
       case vec_construct:
+      case vec_deconstruct:
        elements = TYPE_VECTOR_SUBPARTS (vectype);
        if (LASX_SUPPORTED_MODE_P (mode) && !LSX_SUPPORTED_MODE_P (mode))
          return elements / 2 + 3;
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 3be5606ba01..29d9aaf1ffd 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -14065,6 +14065,7 @@ riscv_builtin_vectorization_cost (enum 
vect_cost_for_stmt type_of_cost,
       return fp ? common_costs->fp_stmt_cost : common_costs->int_stmt_cost;
 
     case vec_construct:
+    case vec_deconstruct:
        {
          /* TODO: This is too pessimistic in case we can splat.  */
          int regmove_cost = fp ? get_fr2vr_cost () : get_gr2vr_cost ();
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 5562d612b22..afe5d45c125 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -5113,6 +5113,7 @@ rs6000_builtin_vectorization_cost (enum 
vect_cost_for_stmt type_of_cost,
        return 2;
 
       case vec_construct:
+      case vec_deconstruct:
        /* This is a rough approximation assuming non-constant elements
           constructed into a vector via element insertion.  FIXME:
           vec_construct is not granular enough for uniformly good
diff --git a/gcc/config/s390/s390.cc b/gcc/config/s390/s390.cc
index bd2adf6bfa1..1bddd5e454a 100644
--- a/gcc/config/s390/s390.cc
+++ b/gcc/config/s390/s390.cc
@@ -4385,6 +4385,7 @@ s390_builtin_vectorization_cost (enum vect_cost_for_stmt 
type_of_cost,
        return 3;
 
       case vec_construct:
+      case vec_deconstruct:
        return TYPE_VECTOR_SUBPARTS (vectype) - 1;
 
       default:
diff --git a/gcc/target.h b/gcc/target.h
index 68ba626da6a..67b04f90f45 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -212,7 +212,8 @@ enum vect_cost_for_stmt
   cond_branch_taken,
   vec_perm,
   vec_promote_demote,
-  vec_construct
+  vec_construct,
+  vec_deconstruct
 };
 
 /* Separate locations for which the vectorizer cost model should
diff --git a/gcc/targhooks.cc b/gcc/targhooks.cc
index 670bc7aa22c..113d8836bea 100644
--- a/gcc/targhooks.cc
+++ b/gcc/targhooks.cc
@@ -777,6 +777,7 @@ default_builtin_vectorization_cost (enum vect_cost_for_stmt 
type_of_cost,
         return 3;
 
       case vec_construct:
+      case vec_deconstruct:
        return estimated_poly_value (TYPE_VECTOR_SUBPARTS (vectype)) - 1;
 
       default:
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index b6e5a864108..d9c218449c0 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -4757,10 +4757,10 @@ vect_model_reduction_cost (loop_vec_info loop_vinfo,
                                        node, 0, vect_body);
       else
        {
-         /* Use NELEMENTS extracts and NELEMENTS scalar ops.  */
+         /* Use NCOPIES deconstructs and NELEMENTS scalar ops.  */
          unsigned int nelements = ncopies * vect_nunits_for_cost (vectype);
-         inside_cost = record_stmt_cost (cost_vec, nelements,
-                                         vec_to_scalar, node, 0,
+         inside_cost = record_stmt_cost (cost_vec, ncopies,
+                                         vec_deconstruct, node, 0,
                                          vect_body);
          inside_cost += record_stmt_cost (cost_vec, nelements,
                                           scalar_stmt, node, 0,
@@ -4822,9 +4822,8 @@ vect_model_reduction_cost (loop_vec_info loop_vinfo,
        {
          unsigned estimated_nunits = vect_nunits_for_cost (vectype);
          /* Extraction of scalar elements.  */
-         epilogue_cost += record_stmt_cost (cost_vec,
-                                            2 * estimated_nunits,
-                                            vec_to_scalar, node, 0,
+         epilogue_cost += record_stmt_cost (cost_vec, 2,
+                                            vec_deconstruct, node, 0,
                                             vect_epilogue);
          /* Scalar max reductions via COND_EXPR / MAX_EXPR.  */
          epilogue_cost += record_stmt_cost (cost_vec,
diff --git a/gcc/tree-vect-stmts.cc b/gcc/tree-vect-stmts.cc
index 4e7b45f5a6c..e991e861525 100644
--- a/gcc/tree-vect-stmts.cc
+++ b/gcc/tree-vect-stmts.cc
@@ -8654,12 +8654,12 @@ vectorizable_store (vec_info *vinfo,
                inside_cost
                  += record_stmt_cost (cost_vec, n_adjacent_stores,
                                       scalar_store, slp_node, 0, vect_body);
-             /* Only need vector extracting when there are more
-                than one stores.  */
+             /* Only need vector deconstruction when there is more
+                than one store.  */
              if (nstores > 1)
                inside_cost
-                 += record_stmt_cost (cost_vec, n_adjacent_stores,
-                                      vec_to_scalar, slp_node, 0, vect_body);
+                 += record_stmt_cost (cost_vec, ncopies,
+                                      vec_deconstruct, slp_node, 0, vect_body);
            }
          if (dump_enabled_p ())
            dump_printf_loc (MSG_NOTE, vect_location,
@@ -9222,11 +9222,11 @@ vectorizable_store (vec_info *vinfo,
                     (we assume the scalar scaling and ptr + offset add is
                     consumed by the load).  */
                  inside_cost
-                   += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
+                   += record_stmt_cost (cost_vec, 1, vec_deconstruct,
                                         slp_node, 0, vect_body);
                  /* N scalar stores plus extracting the elements.  */
                  inside_cost
-                   += record_stmt_cost (cost_vec, cnunits, vec_to_scalar,
+                   += record_stmt_cost (cost_vec, 1, vec_deconstruct,
                                         slp_node, 0, vect_body);
                  inside_cost
                    += record_stmt_cost (cost_vec, cnunits, scalar_store,
@@ -11201,8 +11201,7 @@ vectorizable_load (vec_info *vinfo,
                {
                  /* For emulated gathers N offset vector element
                     offset add is consumed by the load).  */
-                 inside_cost = record_stmt_cost (cost_vec, const_nunits,
-                                                 vec_to_scalar,
+                 inside_cost = record_stmt_cost (cost_vec, 1, vec_deconstruct,
                                                  slp_node, 0, vect_body);
                  /* N scalar loads plus gathering them into a
                     vector.  */
diff --git a/gcc/tree-vectorizer.cc b/gcc/tree-vectorizer.cc
index ab455c08349..8c824e4ee33 100644
--- a/gcc/tree-vectorizer.cc
+++ b/gcc/tree-vectorizer.cc
@@ -169,6 +169,9 @@ dump_stmt_cost (FILE *f, int count, enum vect_cost_for_stmt 
kind,
     case vec_construct:
       ks = "vec_construct";
       break;
+    case vec_deconstruct:
+      ks = "vec_deconstruct";
+      break;
     }
   fprintf (f, "%s ", ks);
   if (kind == unaligned_load || kind == unaligned_store)
-- 
2.51.0

Reply via email to