On Fri, 4 Sep 2026, Pengfei Li wrote:
>
> On 03/09/2026 15:07, Richard Biener wrote:
> > 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.
>
> Thanks for pointing out this.
>
> PR125177 seems to be about the scalar coverage in BB SLP. Could it also be an
> issue in loop SLP? My impression is that shared scalar coverage across
> iterations are usually loop invariants and they are usually hoisted outside
> the loop before vectorization.
I never tested the SLP graph partitioning code on loop SLP, there might
be unexpected differences. I suspect since you exclude externs/constants
that are not uniform things will be fine but those might be the area
where differences might show up.
> btw, do you plan to address this in the near future?
It's on my list ... but given it "only" affects costing currently it
wasn't high priority.
Richard.
> Thanks,
> Pengfei
>
>
> >
> > 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)