On Thu, 27 Aug 2026, Pengfei Li wrote:
> The existing SLP graph partitioning code is specific to BB SLP. This
> patch generalizes it so that it can also be used by loop SLP to support
> reverse permutations elision.
>
> This adds a leader_instance member to _slp_instance. It points to the
> leader instance of the connected SLP subgraph containing the current
> instance, or NULL if the graph has not been partitioned.
Hmm, so you are now relying on vect_bb_partition_graph to be
conservatively correct, for now it's only used for costing.
There is PR125177 which says it is not correct.
Otherwise this looks reasonable.
> Bootstrapped and tested on aarch64-linux-gnu and x86_64-linux-gnu.
>
> gcc/ChangeLog:
>
> * tree-vect-slp.cc (vect_partition_graph): Renamed from
> vect_bb_partition_graph and generalized.
> (vect_build_slp_instance): Initialize leader_instance.
> (vect_analyze_slp_reduc_chain): Likewise.
> (vect_analyze_slp_reduction): Likewise.
> (vect_analyze_slp_reduction_group): Likewise.
> (vect_analyze_slp_instance): Likewise.
> (vect_partition_graph_r): Renamed from
> vect_bb_partition_graph_r and adjusted.
> (vect_bb_slp_scalar_cost): Update comments.
> (vect_slp_analyze_bb_1): Adjust call to vect_partition_graph.
> * tree-vectorizer.h (_slp_instance::leader_instance): New
> member.
> ---
> gcc/tree-vect-slp.cc | 53 ++++++++++++++++++++++++++-----------------
> gcc/tree-vectorizer.h | 6 ++++-
> 2 files changed, 37 insertions(+), 22 deletions(-)
>
> diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
> index d8884fbd88a..fc08d10b872 100644
> --- a/gcc/tree-vect-slp.cc
> +++ b/gcc/tree-vect-slp.cc
> @@ -69,6 +69,7 @@ static int vectorizable_slp_permutation_1 (vec_info *,
> gimple_stmt_iterator *,
> vec<slp_tree> &, bool);
> static void vect_print_slp_tree (dump_flags_t, dump_location_t, slp_tree);
> static bool vect_slp_can_convert_to_external (const vec<stmt_vec_info> &);
> +static void vect_partition_graph (vec_info *);
>
> static object_allocator<_slp_tree> *slp_tree_pool;
> static slp_tree slp_first_node;
> @@ -4210,6 +4211,7 @@ vect_build_slp_instance (vec_info *vinfo,
> SLP_INSTANCE_KIND (new_instance) = kind;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> if (dump_enabled_p ())
> @@ -4583,6 +4585,7 @@ vect_analyze_slp_reduc_chain (loop_vec_info vinfo,
> SLP_INSTANCE_KIND (new_instance) = slp_inst_kind_reduc_chain;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> vinfo->slp_instances.safe_push (new_instance);
> @@ -4647,6 +4650,7 @@ vect_analyze_slp_reduc_chain (loop_vec_info vinfo,
> SLP_INSTANCE_KIND (new_instance) = slp_inst_kind_reduc_chain;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> vect_reduc_info reduc_info = info_for_reduction (vinfo, node);
> @@ -4785,6 +4789,7 @@ vect_analyze_slp_reduction (loop_vec_info vinfo,
> SLP_INSTANCE_KIND (new_instance) = kind;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> if (dump_enabled_p ())
> @@ -4855,6 +4860,7 @@ vect_analyze_slp_reduction_group (loop_vec_info
> loop_vinfo,
> SLP_INSTANCE_KIND (new_instance) = slp_inst_kind_reduc_group;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> if (dump_enabled_p ())
> @@ -5079,6 +5085,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
> SLP_INSTANCE_KIND (new_instance) = kind;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> if (dump_enabled_p ())
> @@ -5318,6 +5325,7 @@ vect_analyze_slp_instance (vec_info *vinfo,
> SLP_INSTANCE_KIND (new_instance) = kind;
> new_instance->reduc_phis = NULL;
> new_instance->cost_vec = vNULL;
> + new_instance->leader_instance = NULL;
> new_instance->subgraph_entries = vNULL;
>
> if (dump_enabled_p ())
> @@ -9511,7 +9519,7 @@ get_ultimate_leader (slp_instance instance,
> }
>
> namespace {
> -/* Subroutine of vect_bb_partition_graph_r. Map KEY to INSTANCE in
> +/* Subroutine of vect_partition_graph_r. Map KEY to INSTANCE in
> KEY_TO_INSTANCE, making INSTANCE the leader of any previous mapping
> for KEY. Return true if KEY was already in KEY_TO_INSTANCE.
>
> @@ -9543,14 +9551,13 @@ vect_map_to_instance (slp_instance instance, T key,
> }
> }
>
> -/* Worker of vect_bb_partition_graph, recurse on NODE. */
> +/* Worker of vect_partition_graph, recurse on NODE. */
>
> static void
> -vect_bb_partition_graph_r (bb_vec_info bb_vinfo,
> - slp_instance instance, slp_tree node,
> - hash_map<stmt_vec_info, slp_instance>
> &stmt_to_instance,
> - hash_map<slp_tree, slp_instance> &node_to_instance,
> - hash_map<slp_instance, slp_instance>
> &instance_leader)
> +vect_partition_graph_r (slp_instance instance, slp_tree node,
> + hash_map<stmt_vec_info, slp_instance> &stmt_to_instance,
> + hash_map<slp_tree, slp_instance> &node_to_instance,
> + hash_map<slp_instance, slp_instance> &instance_leader)
> {
> for (auto stmt_info : SLP_TREE_SCALAR_STMTS (node))
> if (stmt_info)
> @@ -9563,16 +9570,16 @@ vect_bb_partition_graph_r (bb_vec_info bb_vinfo,
>
> for (auto child : SLP_TREE_CHILDREN (node))
> if (child && SLP_TREE_DEF_TYPE (child) == vect_internal_def)
> - vect_bb_partition_graph_r (bb_vinfo, instance, child, stmt_to_instance,
> - node_to_instance, instance_leader);
> + vect_partition_graph_r (instance, child, stmt_to_instance,
> + node_to_instance, instance_leader);
> }
>
> -/* Partition the SLP graph into pieces that can be costed independently. */
> +/* Partition the SLP graph into connected subgraphs. */
>
> static void
> -vect_bb_partition_graph (bb_vec_info bb_vinfo)
> +vect_partition_graph (vec_info *vinfo)
> {
> - DUMP_VECT_SCOPE ("vect_bb_partition_graph");
> + DUMP_VECT_SCOPE ("vect_partition_graph");
>
> /* First walk the SLP graph assigning each involved scalar stmt a
> corresponding SLP graph entry and upon visiting a previously
> @@ -9581,20 +9588,24 @@ vect_bb_partition_graph (bb_vec_info bb_vinfo)
> hash_map<slp_tree, slp_instance> node_to_instance;
> hash_map<slp_instance, slp_instance> instance_leader;
> slp_instance instance;
> - for (unsigned i = 0; bb_vinfo->slp_instances.iterate (i, &instance); ++i)
> + for (unsigned i = 0; vinfo->slp_instances.iterate (i, &instance); ++i)
> {
> instance_leader.put (instance, instance);
> - vect_bb_partition_graph_r (bb_vinfo,
> - instance, SLP_INSTANCE_TREE (instance),
> - stmt_to_instance, node_to_instance,
> - instance_leader);
> + vect_partition_graph_r (instance, SLP_INSTANCE_TREE (instance),
> + stmt_to_instance, node_to_instance,
> + instance_leader);
> }
>
> /* Then collect entries to each independent subgraph. */
> - for (unsigned i = 0; bb_vinfo->slp_instances.iterate (i, &instance); ++i)
> + for (unsigned i = 0; vinfo->slp_instances.iterate (i, &instance); ++i)
> {
> slp_instance leader = get_ultimate_leader (instance, instance_leader);
> - leader->subgraph_entries.safe_push (instance);
> + instance->leader_instance = leader;
> +
> + /* Collect subgraph_entries only for BB SLP. */
> + if (is_a <bb_vec_info> (vinfo))
> + leader->subgraph_entries.safe_push (instance);
> +
> if (dump_enabled_p ()
> && leader != instance)
> dump_printf_loc (MSG_NOTE, vect_location,
> @@ -9653,7 +9664,7 @@ vect_bb_slp_scalar_cost (bb_vec_info vinfo,
> continue;
> }
>
> - /* The following assert verifies that vect_bb_partition_graph
> + /* The following assert verifies that vect_partition_graph
> partitions the SLP graph in a way that each scalar stmt of
> the coverage of the SLP graph belongs to exactly one subgraph.
> ??? This is currently not guaranteed since the function
> @@ -10344,7 +10355,7 @@ vect_slp_analyze_bb_1 (bb_vec_info bb_vinfo, int
> n_stmts, bool &fatal,
> /* Compute vectorizable live stmts. */
> vect_bb_slp_mark_live_stmts (bb_vinfo);
>
> - vect_bb_partition_graph (bb_vinfo);
> + vect_partition_graph (bb_vinfo);
>
> return true;
> }
> diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
> index 4d542d57e6d..d8b1bef98cd 100644
> --- a/gcc/tree-vectorizer.h
> +++ b/gcc/tree-vectorizer.h
> @@ -449,7 +449,11 @@ public:
> /* Vector cost of this entry to the SLP graph. */
> stmt_vector_for_cost cost_vec;
>
> - /* If this instance is the main entry of a subgraph the set of
> + /* The leader SLP instance of the connected SLP subgraph containing this
> + instance, or NULL if the graph has not been partitioned. */
> + _slp_instance *leader_instance;
> +
> + /* If this instance is the leader of a connected subgraph, the set of
> entries into the same subgraph, including itself. */
> vec<_slp_instance *> subgraph_entries;
>
>
--
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald, Abhinav Puri; (HRB 36809, AG Nuernberg)