https://gcc.gnu.org/g:7d351b07e5b85c518b5cbe06a6a57cb653911195
commit r17-1655-g7d351b07e5b85c518b5cbe06a6a57cb653911195 Author: Richard Biener <[email protected]> Date: Wed Jun 17 13:19:56 2026 +0200 Add vec_deconstruct costing kind 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. * 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. Diff: --- 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 42e56512c616..c9403ed94e76 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 d24b06a64458..0bc66abe238b 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 b1fd86c2b320..1734996c68a7 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 401119715012..131f7b3f57b6 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 3be5606ba015..29d9aaf1ffde 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 5562d612b22f..afe5d45c1259 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 bd2adf6bfa19..1bddd5e454ae 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 68ba626da6aa..67b04f90f45c 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 670bc7aa22cd..113d8836beae 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 4d9b691c3299..0167d52b28b2 100644 --- a/gcc/tree-vect-loop.cc +++ b/gcc/tree-vect-loop.cc @@ -4752,10 +4752,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, @@ -4817,9 +4817,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 4e7b45f5a6c8..e991e8615253 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 ab455c083498..8c824e4ee33a 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)
