On Tue, 28 Oct 2025, Christopher Bazley wrote:

> The vect_build_slp_instance function has a lot of parameters.
> Hitherto, it was undocumented whether it took ownership of the
> vectors named scalar_stmts, root_stmt_infos and remain.
> 
> The calling code in vect_analyze_slp was written in such a way
> as to assume that vect_build_slp_instance always took ownership
> of the caller's reference to the passed-in scalar_stmts (i.e.
> that the vector need not be released by the caller on failure).

Actually it's written that vect_build_slp_tree takes ownership
on _successs_, but not on failure.  But yes, the code is hard to
follow.  All the wrappers, including vect_build_slp_instance
"deal with this", but it seems

  if (bb_vec_info bb_vinfo = dyn_cast <bb_vec_info> (vinfo))
    {
      for (unsigned i = 0; i < bb_vinfo->roots.length (); ++i)
        {       
          vect_location = bb_vinfo->roots[i].roots[0]->stmt;
          /* Apply patterns.  */
          for (unsigned j = 0; j < bb_vinfo->roots[i].stmts.length (); 
++j)
            bb_vinfo->roots[i].stmts[j]
              = vect_stmt_to_vectorize (bb_vinfo->roots[i].stmts[j]);
          if (vect_build_slp_instance (bb_vinfo, bb_vinfo->roots[i].kind,
                                       bb_vinfo->roots[i].stmts,
                                       bb_vinfo->roots[i].roots,
                                       bb_vinfo->roots[i].remain,
                                       max_tree_size, &limit, bst_map, 
false))
            {
              bb_vinfo->roots[i].stmts = vNULL;
              bb_vinfo->roots[i].roots = vNULL;
              bb_vinfo->roots[i].remain = vNULL;
            }
        }

is broken in that it does not honor vect_build_slp_instance
always taking ownership (but of scalar_stmts only)?

That is, I see there's some issues here, but the
proposed fix does not look correct (see below).

I was hoping auto_vec and std::move and C++ magic could maybe
clean this ownership mess up a bit, but my patience ran out
too fast (a few weeks ago).

> That contract might have been alright in principle (albeit
> inconsistent with the treatment of root_stmt_infos) except that
> vect_build_slp_tree can succeed when called within
> vect_build_slp_instance before vect_build_slp_instance fails.
> 
> vect_build_slp_tree puts a reference to the stmts into the
> bst_map, but does not undo that on the failure recovery path.
> Consequently, the destructor for the _bb_vec_info later
> crashed upon trying to release the stmts of one of its roots
> because the stmts had already been released by the destructor
> of the _slp_tree created by vect_build_slp_tree (when
> invoked via release_scalar_stmts_to_slp_tree_map).
> 
> There was also a potential leak in the case where *limit is 0
> (which causes false to be returned without releasing anything).
> 
> Another broken failure recovery path occurred if
> vect_build_slp_instance detected that unrolling could have
> been required for BB SLP and the maximum number of vector
> elements for the tree was a known constant not greater than
> the group size. In this case, the tree node was freed *and*
> scalar_stmts was released (despite ownership having passed
> to the tree).
> 
> Simplified the implementation of vect_build_slp_instance by
> not calling vect_build_slp_tree until after all other
> checks are completed. Simplified the contract with its
> callers by requiring them to release scalar_stmts on
> failure.
> 
> The "Save for re-processing on failure" code was brittle because if
> the length of scalar_stmts was greater than one and
> vect_build_slp_instance failed then the length of scalar_stmts would
> have been queried again, despite ownership of scalar_stmts having
> already passed to vect_build_slp_instance. We now avoid querying the
> length a second time.
> ---
>  gcc/tree-vect-slp.cc | 127 ++++++++++++++++++++++++-------------------
>  1 file changed, 72 insertions(+), 55 deletions(-)
> 
> diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
> index 89bbd13fcb9..8b66751a8a9 100644
> --- a/gcc/tree-vect-slp.cc
> +++ b/gcc/tree-vect-slp.cc
> @@ -4062,7 +4062,9 @@ vect_build_slp_store_interleaving (vec<slp_tree> 
> &rhs_nodes,
>  }
>  
>  /* Analyze an SLP instance starting from SCALAR_STMTS which are a group
> -   of KIND.  Return true if successful.  */
> +   of KIND.  Return true if successful.  VEC_INFO and BST_MAP take joint
> +   ownership of SCALAR_STMTS if successful.  VEC_INFO takes ownership of
> +   ROOT_STMT_INFOS and REMAIN if successful.  */
>  
>  static bool
>  vect_build_slp_instance (vec_info *vinfo,
> @@ -4115,10 +4117,6 @@ vect_build_slp_instance (vec_info *vinfo,
>        matches[1] = false;
>      }
>    else
> -    node = vect_build_slp_tree (vinfo, scalar_stmts, group_size,
> -                             &nunits, matches, limit,
> -                             &tree_size, bst_map);
> -  if (node != NULL)
>      {
>        /* Calculate the unrolling factor based on the smallest type.  */
>        poly_uint64 unrolling_factor

Here we use max_nunits and that's set by vect_build_slp_tree so I don't
see how you can delay that.

> @@ -4136,7 +4134,6 @@ vect_build_slp_instance (vec_info *vinfo,
>                                "Build SLP failed: store group "
>                                "size not a multiple of the vector size "
>                                "in basic block SLP\n");
> -           vect_free_slp_tree (node);
>             return false;
>           }
>         /* Fatal mismatch.  */
> @@ -4146,46 +4143,52 @@ vect_build_slp_instance (vec_info *vinfo,
>                            "splitting\n");
>         memset (matches, true, group_size);
>         matches[group_size / const_max_nunits * const_max_nunits] = false;
> -       vect_free_slp_tree (node);
>       }
> -      else
> +     else
>       {
> -       /* Create a new SLP instance.  */
> -       slp_instance new_instance = XNEW (class _slp_instance);
> -       SLP_INSTANCE_TREE (new_instance) = node;
> -       SLP_INSTANCE_LOADS (new_instance) = vNULL;
> -       SLP_INSTANCE_ROOT_STMTS (new_instance) = root_stmt_infos;
> -       SLP_INSTANCE_REMAIN_DEFS (new_instance) = remain;
> -       SLP_INSTANCE_KIND (new_instance) = kind;
> -       new_instance->reduc_phis = NULL;
> -       new_instance->cost_vec = vNULL;
> -       new_instance->subgraph_entries = vNULL;
> +       node = vect_build_slp_tree (vinfo, scalar_stmts, group_size, &nunits,
> +                                   matches, limit, &tree_size, bst_map);
> +     }
> +    }
>  
> -       if (dump_enabled_p ())
> -         dump_printf_loc (MSG_NOTE, vect_location,
> -                          "SLP size %u vs. limit %u.\n",
> -                          tree_size, max_tree_size);
> +  if (node != NULL)
> +    {
> +      /* Create a new SLP instance.  */
> +      slp_instance new_instance = XNEW (class _slp_instance);
> +      SLP_INSTANCE_TREE (new_instance) = node;
> +      SLP_INSTANCE_LOADS (new_instance) = vNULL;
> +      SLP_INSTANCE_ROOT_STMTS (new_instance) = root_stmt_infos;
> +      SLP_INSTANCE_REMAIN_DEFS (new_instance) = remain;
> +      SLP_INSTANCE_KIND (new_instance) = kind;
> +      new_instance->reduc_phis = NULL;
> +      new_instance->cost_vec = vNULL;
> +      new_instance->subgraph_entries = vNULL;
>  
> -       vinfo->slp_instances.safe_push (new_instance);
> +      if (dump_enabled_p ())
> +     dump_printf_loc (MSG_NOTE, vect_location, "SLP size %u vs limit %u.\n",
> +                      tree_size, max_tree_size);
>  
> -       /* ???  We've replaced the old SLP_INSTANCE_GROUP_SIZE with
> -          the number of scalar stmts in the root in a few places.
> -          Verify that assumption holds.  */
> -       gcc_assert (SLP_TREE_SCALAR_STMTS (SLP_INSTANCE_TREE (new_instance))
> -                     .length () == group_size);
> +      vinfo->slp_instances.safe_push (new_instance);
>  
> -       if (dump_enabled_p ())
> -         {
> -           dump_printf_loc (MSG_NOTE, vect_location,
> -                            "Final SLP tree for instance %p:\n",
> -                            (void *) new_instance);
> -           vect_print_slp_graph (MSG_NOTE, vect_location,
> -                                 SLP_INSTANCE_TREE (new_instance));
> -         }
> +      /* ???  We've replaced the old SLP_INSTANCE_GROUP_SIZE with
> +      the number of scalar stmts in the root in a few places.
> +      Verify that assumption holds.  */
> +      gcc_assert (
> +     SLP_TREE_SCALAR_STMTS (SLP_INSTANCE_TREE (new_instance)).length ()
> +     == group_size);
>  
> -       return true;
> +      if (dump_enabled_p ())
> +     {
> +       dump_printf_loc (MSG_NOTE, vect_location,
> +                        "Final SLP tree for instance %p:\n",
> +                        (void *) new_instance);
> +       vect_print_slp_graph (MSG_NOTE, vect_location,
> +                             SLP_INSTANCE_TREE (new_instance));
>       }
> +
> +      return true;
>      }
> +
>    /* Failed to SLP.  */
>  
>    /* While we arrive here even with slp_inst_kind_store we should only
> @@ -4193,9 +4196,6 @@ vect_build_slp_instance (vec_info *vinfo,
>       vect_analyze_slp_instance now.  */
>    gcc_assert (kind != slp_inst_kind_store || group_size == 1);
>  
> -  /* Free the allocated memory.  */
> -  scalar_stmts.release ();
> -
>    /* Failed to SLP.  */
>    if (dump_enabled_p ())
>      dump_printf_loc (MSG_NOTE, vect_location, "SLP discovery failed\n");
> @@ -4699,7 +4699,6 @@ vect_analyze_slp_reduction (loop_vec_info vinfo,
>        return true;
>      }
>    /* Failed to SLP.  */
> -
>    /* Free the allocated memory.  */
>    scalar_stmts.release ();
>  
> @@ -5560,8 +5559,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>           if (! vect_build_slp_instance (vinfo, slp_inst_kind_store,
>                                          stmts, roots, remain, max_tree_size,
>                                          &limit, bst_map, force_single_lane))
> -           return opt_result::failure_at (vect_location,
> -                                          "SLP build failed.\n");
> +           {
> +             stmts.release ();
> +             return opt_result::failure_at (vect_location,
> +                                            "SLP build failed.\n");
> +           }
>         }
>  
>        stmt_vec_info stmt_info;
> @@ -5575,8 +5577,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>         if (! vect_build_slp_instance (vinfo, slp_inst_kind_store,
>                                        stmts, roots, remain, max_tree_size,
>                                        &limit, bst_map, force_single_lane))
> -         return opt_result::failure_at (vect_location,
> -                                        "SLP build failed.\n");
> +         {
> +           stmts.release ();
> +           return opt_result::failure_at (vect_location,
> +                                          "SLP build failed.\n");
> +         }
>       }
>      }
>  
> @@ -5634,8 +5639,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                                        max_tree_size, &limit,
>                                                        bst_map,
>                                                        force_single_lane))
> -                 return opt_result::failure_at (vect_location,
> -                                                "SLP build failed.\n");
> +                 {
> +                   scalar_stmts.release ();
> +                   return opt_result::failure_at (vect_location,
> +                                                  "SLP build failed.\n");
> +                }
>               }
>           }
>         /* Save for re-processing on failure.  */
> @@ -5649,8 +5657,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                          max_tree_size, &limit, bst_map,
>                                          force_single_lane))
>           {
> -           if (scalar_stmts.length () <= 1)
> -             scalar_stmts.release ();
> +           scalar_stmts.release ();
>             /* Do SLP discovery for single-lane reductions.  */
>             for (auto stmt_info : saved_stmts)
>               if (! vect_analyze_slp_reduction (loop_vinfo,
> @@ -5691,8 +5698,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                              stmts, roots, remain,
>                                              max_tree_size, &limit,
>                                              bst_map, force_single_lane))
> -               return opt_result::failure_at (vect_location,
> -                                              "SLP build failed.\n");
> +               {
> +                 stmts.release ();
> +                 return opt_result::failure_at (vect_location,
> +                                                "SLP build failed.\n");
> +               }
>             }
>         }
>  
> @@ -5736,6 +5746,7 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                        bst_map, force_single_lane))
>           {
>             roots.release ();
> +           stmts.release ();
>             return opt_result::failure_at (vect_location,
>                                            "SLP build failed.\n");
>           }
> @@ -5760,8 +5771,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                              stmts, roots, remain,
>                                              max_tree_size, &limit,
>                                              bst_map, force_single_lane))
> -               return opt_result::failure_at (vect_location,
> -                                              "SLP build failed.\n");
> +               {
> +                 stmts.release ();
> +                 return opt_result::failure_at (vect_location,
> +                                                "SLP build failed.\n");
> +               }
>             }
>           /* When the latch def is from a different cycle this can only
>              be a induction.  Build a simple instance for this.
> @@ -5778,8 +5792,11 @@ vect_analyze_slp (vec_info *vinfo, unsigned 
> max_tree_size,
>                                              stmts, roots, remain,
>                                              max_tree_size, &limit,
>                                              bst_map, force_single_lane))
> -               return opt_result::failure_at (vect_location,
> -                                              "SLP build failed.\n");
> +               {
> +                 stmts.release ();
> +                 return opt_result::failure_at (vect_location,
> +                                                "SLP build failed.\n");
> +               }
>             }
>         }
>      }
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to