> -----Original Message-----
> From: Richard Biener <[email protected]>
> Sent: Monday, July 6, 2026 4:03 PM
> To: Liu, Hongtao <[email protected]>
> Cc: [email protected]
> Subject: Re: [PATCH] i386: Move SLP-node costing into
> ix86_vector_costs::add_slp_cost
> 
> On Wed, 1 Jul 2026, liuhongt wrote:
> 
> > Override the add_slp_cost hook so the x86 cost model gets the recorded
> > stmt costs grouped per SLP node.  The node-dependent costing that used
> > to live in add_stmt_cost -- the
> > vec_construct/vec_deconstruct/scalar_to_vec
> > construction cost and the cross-lane vec_perm accounting -- is moved
> > to add_slp_cost, which handles those kinds and delegates the rest to
> > add_stmt_cost.  The shared tail (default-cost fallback,
> > Bonnell/Silvermont fixups and frequency scaling) is factored into
> > finish_stmt_cost, called by both paths.
> >
> > This is a refactor with no intended functional change.
> >
> > Bootstrapped and regtested on x86_64-pc-linux-gnu{-m32,}.
> > Ok for trunk?
> 
> Sorry for not commenting earlier
> 
> > gcc/ChangeLog:
> >
> >     * config/i386/i386.cc (ix86_vector_costs): Declare add_slp_cost,
> >     ix86_slp_construct_cost, ix86_slp_account_perm and
> finish_stmt_cost.
> >     (ix86_vector_costs::add_stmt_cost): Move the vec_construct and
> >     vec_perm node costing out; finish via finish_stmt_cost.
> >     (ix86_vector_costs::ix86_slp_construct_cost): New.
> >     (ix86_vector_costs::ix86_slp_account_perm): New.
> >     (ix86_vector_costs::finish_stmt_cost): New.
> >     (ix86_vector_costs::add_slp_cost): New.
> > ---
> >  gcc/config/i386/i386.cc | 166
> > ++++++++++++++++++++++++++++++++--------
> >  1 file changed, 135 insertions(+), 31 deletions(-)
> >
> > diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index
> > e66958db7ac..94c2b3c0090 100644
> > --- a/gcc/config/i386/i386.cc
> > +++ b/gcc/config/i386/i386.cc
> > @@ -26165,6 +26165,9 @@ public:
> >                           stmt_vec_info stmt_info, slp_tree node,
> >                           tree vectype, int misalign,
> >                           vect_cost_model_location where) override;
> > +  unsigned int add_slp_cost (slp_tree node,
> > +                        const array_slice<stmt_info_for_cost> &)
> > +                        override;
> >    void finish_cost (const vector_costs *) override;
> >    bool better_main_loop_than_p (const vector_costs *) const override;
> >    bool better_epilogue_loop_than_p (const vector_costs *other, @@
> > -26174,6 +26177,20 @@ private:
> >
> >    /* Estimate register pressure of the vectorized code.  */
> >    void ix86_vect_estimate_reg_pressure ();
> > +  /* Cost of a vec_construct/vec_deconstruct/scalar_to_vec of SLP NODE,
> > +     or -1 to fall back to the default vector cost.  */
> > +  int ix86_slp_construct_cost (slp_tree node, vect_cost_for_stmt kind,
> > +                          tree vectype, machine_mode mode, bool fp,
> > +                          vect_cost_model_location where);
> > +  /* Account a vec_perm of SLP NODE to the cross-lane permute
> > +counters.  */
> > +  void ix86_slp_account_perm (slp_tree node, int count, tree vectype,
> > +                         stmt_vec_info stmt_info,
> > +                         vect_cost_model_location where);
> > +  /* Common cost finalization shared by add_stmt_cost and
> > +add_slp_cost.  */
> > +  unsigned int finish_stmt_cost (int stmt_cost, int count,
> > +                            vect_cost_for_stmt kind,
> > +                            stmt_vec_info stmt_info, machine_mode
> mode,
> > +                            tree vectype, vect_cost_model_location
> where);
> >    /* Number of GENERAL_REGS/SSE_REGS used in the vectorizer, it's used for
> >       estimation of register pressure.
> >       ??? Currently it's only used by vec_construct/scalar_to_vec @@
> > -26255,7 +26272,6 @@ ix86_vector_costs::add_stmt_cost (int count,
> vect_cost_for_stmt kind,
> >                               tree vectype, int,
> >                               vect_cost_model_location where)  {
> > -  unsigned retval = 0;
> >    bool scalar_p
> >      = (kind == scalar_stmt || kind == scalar_load || kind == scalar_store);
> >    int stmt_cost = - 1;
> > @@ -26732,18 +26748,35 @@ ix86_vector_costs::add_stmt_cost (int
> count, vect_cost_for_stmt kind,
> >                 + ix86_vec_cost (mode, ix86_cost->sse_op);
> >      }
> >
> > +  /* vec_construct/vec_deconstruct/scalar_to_vec and vec_perm are costed
> > +     per SLP node in add_slp_cost, which does the node-specific work before
> > +     finishing here.  */
> > +  return finish_stmt_cost (stmt_cost, count, kind, stmt_info, mode,
> vectype,
> > +                      where);
> > +}
> > +
> > +/* See the comment above the declaration for details.  */
> > +
> > +int
> > +ix86_vector_costs::ix86_slp_construct_cost (slp_tree node,
> > +                                       vect_cost_for_stmt kind,
> > +                                       tree vectype, machine_mode mode,
> > +                                       bool fp,
> > +                                       vect_cost_model_location where) {
> > +  int stmt_cost = -1;
> > +
> >    /* If we do elementwise loads into a vector then we are bound by
> >       latency and execution resources for the many scalar loads
> >       (AGU and load ports).  Try to account for this by scaling the
> >       construction cost by the number of elements involved.  */
> >    if ((kind == vec_construct || kind == vec_deconstruct)
> > -      && ((node
> > -      && (((SLP_TREE_MEMORY_ACCESS_TYPE (node) ==
> VMAT_ELEMENTWISE
> > -            || SLP_TREE_MEMORY_ACCESS_TYPE (node) ==
> VMAT_STRIDED_SLP)
> > -           && (TREE_CODE (DR_STEP (STMT_VINFO_DATA_REF
> > -                                   (SLP_TREE_REPRESENTATIVE
> (node))))
> > -               != INTEGER_CST))
> > -          || mat_gather_scatter_p (SLP_TREE_MEMORY_ACCESS_TYPE
> (node))))))
> > +      && (((SLP_TREE_MEMORY_ACCESS_TYPE (node) ==
> VMAT_ELEMENTWISE
> > +       || SLP_TREE_MEMORY_ACCESS_TYPE (node) ==
> VMAT_STRIDED_SLP)
> > +      && (TREE_CODE (DR_STEP (STMT_VINFO_DATA_REF
> > +                              (SLP_TREE_REPRESENTATIVE (node))))
> > +          != INTEGER_CST))
> > +     || mat_gather_scatter_p (SLP_TREE_MEMORY_ACCESS_TYPE
> (node))))
> >      {
> >        auto lsdata = static_cast<vect_load_store_data *> (node->data);
> >        tree ls_type = lsdata->ls_type ? lsdata->ls_type : vectype; @@
> > -26755,7 +26788,6 @@ ix86_vector_costs::add_stmt_cost (int count,
> vect_cost_for_stmt kind,
> >                 / GET_MODE_BITSIZE (TYPE_MODE (ls_eltype)) + 1);
> >      }
> >    else if ((kind == vec_construct || kind == scalar_to_vec)
> > -      && node
> >        && SLP_TREE_DEF_TYPE (node) == vect_external_def)
> >      {
> >        stmt_cost = ix86_default_vector_cost (kind, mode); @@ -26823,34
> > +26855,58 @@ ix86_vector_costs::add_stmt_cost (int count,
> vect_cost_for_stmt kind,
> >     if (TREE_CODE (op) == SSA_NAME)
> >       TREE_VISITED (op) = 0;
> >      }
> > -  if (stmt_cost == -1)
> > -    stmt_cost = ix86_default_vector_cost (kind, mode);
> >
> > +  return stmt_cost;
> > +}
> > +
> > +/* See the comment above the declaration for details.  */
> > +
> > +void
> > +ix86_vector_costs::ix86_slp_account_perm (slp_tree node, int count,
> > +                                     tree vectype,
> > +                                     stmt_vec_info stmt_info,
> > +                                     vect_cost_model_location where) {
> >    /* BIT_FIELD_REF <vect_**, 64, 0> with count 0 costs 0 in body.  */
> > -  if (kind == vec_perm && vectype && count != 0)
> > -    {
> > -      unsigned vec_size = GET_MODE_SIZE (TYPE_MODE (vectype));
> > -      unsigned nunits = TYPE_VECTOR_SUBPARTS (vectype);
> > -      unsigned *num_vec_perm = NULL;
> > +  if (!vectype || count == 0)
> > +    return;
> >
> > -      if (vec_size == 32)
> > -   num_vec_perm = m_num_avx256_vec_perm;
> > -      else if (vec_size == 64)
> > -   num_vec_perm = m_num_avx512_vec_perm;
> > +  unsigned vec_size = GET_MODE_SIZE (TYPE_MODE (vectype));  unsigned
> > + nunits = TYPE_VECTOR_SUBPARTS (vectype);  unsigned *num_vec_perm =
> > + NULL;
> >
> > -      if (num_vec_perm && ix86_count_cross_lane_perm_p (m_vinfo, node,
> nunits))
> > +  if (vec_size == 32)
> > +    num_vec_perm = m_num_avx256_vec_perm;  else if (vec_size == 64)
> > +    num_vec_perm = m_num_avx512_vec_perm;
> > +
> > +  if (num_vec_perm && ix86_count_cross_lane_perm_p (m_vinfo, node,
> nunits))
> > +    {
> > +      num_vec_perm[where] += count;
> > +      if (dump_file && (dump_flags & TDF_DETAILS))
> >     {
> > -     num_vec_perm[where] += count;
> > -     if (dump_file && (dump_flags & TDF_DETAILS))
> > -       {
> > -         fprintf (dump_file,
> > -                  "Detected avx%u cross-lane permutation: ", vec_size * 8);
> > -         if (stmt_info)
> > -           print_gimple_expr (dump_file, stmt_info->stmt, 0, TDF_SLIM);
> > -         fprintf (dump_file, " \n");
> > -       }
> > +     fprintf (dump_file,
> > +              "Detected avx%u cross-lane permutation: ", vec_size * 8);
> > +     if (stmt_info)
> > +       print_gimple_expr (dump_file, stmt_info->stmt, 0, TDF_SLIM);
> > +     fprintf (dump_file, " \n");
> >     }
> >      }
> > +}
> > +
> > +/* Apply the default-cost fallback, uarch fixups and frequency scaling to
> > +   STMT_COST (-1 if not yet computed), accumulate into m_costs[WHERE]
> and
> > +   return the result.  */
> > +
> > +unsigned int
> > +ix86_vector_costs::finish_stmt_cost (int stmt_cost, int count,
> > +                                vect_cost_for_stmt kind,
> > +                                stmt_vec_info stmt_info,
> > +                                machine_mode mode, tree vectype,
> > +                                vect_cost_model_location where) {
> > +  if (stmt_cost == -1)
> > +    stmt_cost = ix86_default_vector_cost (kind, mode);
> >
> >    /* Penalize DFmode vector operations for Bonnell.  */
> >    if (TARGET_CPU_P (BONNELL) && kind == vector_stmt @@ -26860,7
> > +26916,8 @@ ix86_vector_costs::add_stmt_cost (int count,
> vect_cost_for_stmt kind,
> >    /* Statements in an inner loop relative to the loop being
> >       vectorized are weighted more heavily.  The value here is
> >       arbitrary and could potentially be improved with analysis.  */
> > -  retval = adjust_cost_for_freq (stmt_info, where, count *
> > stmt_cost);
> > +  unsigned int retval
> > +    = adjust_cost_for_freq (stmt_info, where, count * stmt_cost);
> >
> >    /* We need to multiply all vector stmt cost by 1.7 (estimated cost)
> >       for Silvermont as it has out of order integer pipeline and can
> > execute @@ -26879,6 +26936,53 @@ ix86_vector_costs::add_stmt_cost
> (int count, vect_cost_for_stmt kind,
> >    return retval;
> >  }
> >
> > +/* Cost the entries of COST_VEC, which all belong to a single SLP node.
> > +   vec_construct/vec_deconstruct/scalar_to_vec and vec_perm get x86-
> specific
> > +   node-level costing here; everything else is handed to
> > +add_stmt_cost.  */
> > +
> > +unsigned int
> > +ix86_vector_costs::add_slp_cost (slp_tree,
> > +                            const array_slice<stmt_info_for_cost>
> &cost_vec) {
> > +  unsigned int sum = 0;
> > +  for (auto item : cost_vec)
> 
> So my original intent of the ::add_slp_cost hook was to make it possible to 
> key
> only on the 'node' - the passed cost_vec should have been possibly just an
> afterthought.
> 
> So if you iterate over the cost_vec and ignore the common node here there's
> no immediate benefit to how we deal with this previously?

I thought you wanted to move all SLP-related processing into add_slp_cost, so 
that there would be no need to check for the existence of the node in 
add_stmt_cost, and additionally, the case of fold_left_reduction could be 
handled in add_slp_cost

> 
> As said I didn't yet get to experiment on how that works out, but I'd have
> expected sth like
> 
>     if (mat_gather_scatter_p (SLP_TREE_MEMORY_ACCESS_TYPE (node)))
>       ix86_slp_account_gather_scatter (node, cost_vec);
>     else if (SLP_TREE_MEMORY_ACCESS_TYPE (node) == VMAT_STRIDED_SLP)
>       ...
>     else
>       return ::add_slp_cost (node, cost_vec);
> 
> but maybe this doesn't work out to simplify things.
> 
> > +    {
> > +      tree vectype = item.vectype;
> > +      /* vec_perm is accounted even without a node (treated as cross-lane);
> > +    the construct cases need a node.  */
> > +      if (item.kind == vec_perm
> > +     || (item.node
> > +         && (item.kind == vec_construct
> > +             || item.kind == vec_deconstruct
> > +             || item.kind == scalar_to_vec)))
> > +   {
> > +     machine_mode mode = vectype ? TYPE_MODE (vectype) : TImode;
> > +     bool fp = vectype ? FLOAT_TYPE_P (vectype) : false;
> > +     int stmt_cost = -1;
> > +
> > +     if (item.kind == vec_perm)
> > +       ix86_slp_account_perm (item.node, item.count, vectype,
> > +                              item.stmt_info, item.where);
> > +     else
> > +       stmt_cost = ix86_slp_construct_cost (item.node, item.kind, vectype,
> > +                                            mode, fp, item.where);
> > +
> > +     unsigned int cost
> > +       = finish_stmt_cost (stmt_cost, item.count, item.kind,
> > +                           item.stmt_info, mode, vectype, item.where);
> > +     if (dump_file && (dump_flags & TDF_DETAILS))
> > +       dump_stmt_cost (dump_file, item.count, item.kind, item.stmt_info,
> > +                       item.node, vectype, item.misalign, cost,
> > +                       item.where);
> > +     sum += cost;
> > +   }
> > +      else
> > +   sum += ::add_stmt_cost (this, item.count, item.kind, item.stmt_info,
> > +                           item.node, vectype, item.misalign,
> item.where);
> > +    }
> > +  return sum;
> > +}
> > +
> >  void
> >  ix86_vector_costs::ix86_vect_estimate_reg_pressure ()  {
> >
> 
> --
> Richard Biener <[email protected]>
> SUSE Software Solutions Germany GmbH,
> Frankenstrasse 146, 90461 Nuernberg, Germany;
> GF: Jochen Jaser, Andrew McDonald; (HRB 36809, AG Nuernberg)

Reply via email to