On Wed, Sep 2, 2026 at 9:49 PM Richard Biener <[email protected]> wrote:
>
> The vectorizer currently works around the fact that the x86
> backend in its add_stmt_cost hook walks all SLP node scalar
> defs to perform gpr<->xmm move costing when costing vector
> splat/constructor costing for invariants by aoviding to
> pass the SLP node to each part it is costing.  Say for the
> integer vector { 0, 0, 0, 0, a, b, c, d } and V4SImode
> vect_prologue_cost_for_slp creates two cost entries, one
> for the V4SI { 0, 0, 0, 0 } (a load) and one for
> { a, b, c, d }, a vec_construct.  If node was attached to
> both we'd currently cost the grp<->xmm moves for a, b, c, d
> twice.  The following removes this workaround and instead
> applies this costing in the add_slp_cost hook which is
> invoked only once per SLP node.  The actual vec_construct
> cost is still handled by add_stmt_cost.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>
> OK for the x86 part?

Adding stmt_cost directly to m_costs bypasses per-statement dumping.
Can we dump gpr<->xmm cost explicitly in the add_slp_cost?
Others LGTM.
>
> Tamar/Robin, this is a heads-up, not sure if riscv/aarch64 do
> some similar tinkering and rely on vect_prologue_cost_for_slp
> setting 'node' only on one cost element.  Eventually I'll get
> screamed at by the CIs, of course.
>
> Richard.
>
>         * config/i386/i386.cc (ix86_vector_costs::add_stmt_cost):
>         Move gpr<->xmm move cost ...
>         (ix86_vector_costs::add_slp_cost): ... here, to new overload
>         of add_slp_cost.
>         * tree-vect-slp.cc (vect_prologue_cost_for_slp): Consistently
>         set SLP node for all cost components to make grouping for
>         the add_slp_cost hook work.
>         (add_slp_costs): Avoid calling vector_costs::add_slp_cost
>         with NULL SLP node.
> ---
>  gcc/config/i386/i386.cc | 132 ++++++++++++++++++++++------------------
>  gcc/tree-vect-slp.cc    |  21 +++----
>  2 files changed, 82 insertions(+), 71 deletions(-)
>
> diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
> index 9f2196d54de..bd3b12be284 100644
> --- a/gcc/config/i386/i386.cc
> +++ b/gcc/config/i386/i386.cc
> @@ -26518,6 +26518,7 @@ 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, const array_slice<stmt_info_for_cost> 
> &);
>    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,
> @@ -27111,11 +27112,74 @@ ix86_vector_costs::add_stmt_cost (int count, 
> vect_cost_for_stmt kind,
>        stmt_cost *= (GET_MODE_BITSIZE (TYPE_MODE (ls_type))
>                     / 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)
> +  if (stmt_cost == -1)
> +    stmt_cost = ix86_default_vector_cost (kind, mode);
> +
> +  /* 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 (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))
> +           {
> +             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");
> +           }
> +       }
> +    }
> +
> +  /* Penalize DFmode vector operations for Bonnell.  */
> +  if (TARGET_CPU_P (BONNELL) && kind == vector_stmt
> +      && vectype && GET_MODE_INNER (TYPE_MODE (vectype)) == DFmode)
> +    stmt_cost *= 5;  /* FIXME: The value here is arbitrary.  */
> +
> +  /* 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);
> +
> +  /* 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
> +     2 scalar instruction per tick, but has in order SIMD pipeline.  */
> +  if ((TARGET_CPU_P (SILVERMONT) || TARGET_CPU_P (GOLDMONT)
> +       || TARGET_CPU_P (GOLDMONT_PLUS) || TARGET_CPU_P (INTEL))
> +      && stmt_info && stmt_info->stmt)
> +    {
> +      tree lhs_op = gimple_get_lhs (stmt_info->stmt);
> +      if (lhs_op && TREE_CODE (TREE_TYPE (lhs_op)) == INTEGER_TYPE)
> +       retval = (retval * 17) / 10;
> +    }
> +
> +  m_costs[where] += retval;
> +
> +  return retval;
> +}
> +
> +unsigned
> +ix86_vector_costs::add_slp_cost (slp_tree node,
> +                                const array_slice<stmt_info_for_cost> &parts)
> +{
> +  int stmt_cost = 0;
> +
> +  /* For vector construction account for the cost of moving data between
> +     GRP and XMM.  As we are looking at the SLP nodes elements, avoid
> +     duplicate costs by doing this in add_slp_cost, leaving the actual
> +     splat/ctor cost to add_stmt_cost.  */
> +  if (SLP_TREE_DEF_TYPE (node) == vect_external_def)
>      {
> -      stmt_cost = ix86_default_vector_cost (kind, mode);
>        unsigned i;
>        tree op;
>        FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_OPS (node), i, op)
> @@ -27153,7 +27217,7 @@ ix86_vector_costs::add_stmt_cost (int count, 
> vect_cost_for_stmt kind,
>             ;
>           else
>             {
> -             if (fp)
> +             if (FLOAT_TYPE_P (TREE_TYPE (op)))
>                 {
>                   /* Scalar FP values residing in x87 registers need to be
>                      spilled and reloaded.  */
> @@ -27166,11 +27230,11 @@ ix86_vector_costs::add_stmt_cost (int count, 
> vect_cost_for_stmt kind,
>                            + ix86_cost->sse_load[sse_store_index (mode2)]);
>                       stmt_cost += COSTS_N_INSNS (cost) / 2;
>                     }
> -                 m_num_sse_needed[where]++;
> +                 m_num_sse_needed[vect_prologue]++;
>                 }
>               else
>                 {
> -                 m_num_gpr_needed[where]++;
> +                 m_num_gpr_needed[vect_prologue]++;
>
>                   stmt_cost += COSTS_N_INSNS (ix86_cost->integer_to_sse) / 2;
>                 }
> @@ -27179,61 +27243,11 @@ ix86_vector_costs::add_stmt_cost (int count, 
> vect_cost_for_stmt kind,
>        FOR_EACH_VEC_ELT (SLP_TREE_SCALAR_OPS (node), i, op)
>         if (TREE_CODE (op) == SSA_NAME)
>           TREE_VISITED (op) = 0;
> -    }
> -  if (stmt_cost == -1)
> -    stmt_cost = ix86_default_vector_cost (kind, mode);
> -
> -  /* 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 (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))
> -           {
> -             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");
> -           }
> -       }
> +      m_costs[vect_prologue] += stmt_cost;
>      }
>
> -  /* Penalize DFmode vector operations for Bonnell.  */
> -  if (TARGET_CPU_P (BONNELL) && kind == vector_stmt
> -      && vectype && GET_MODE_INNER (TYPE_MODE (vectype)) == DFmode)
> -    stmt_cost *= 5;  /* FIXME: The value here is arbitrary.  */
> -
> -  /* 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);
> -
> -  /* 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
> -     2 scalar instruction per tick, but has in order SIMD pipeline.  */
> -  if ((TARGET_CPU_P (SILVERMONT) || TARGET_CPU_P (GOLDMONT)
> -       || TARGET_CPU_P (GOLDMONT_PLUS) || TARGET_CPU_P (INTEL))
> -      && stmt_info && stmt_info->stmt)
> -    {
> -      tree lhs_op = gimple_get_lhs (stmt_info->stmt);
> -      if (lhs_op && TREE_CODE (TREE_TYPE (lhs_op)) == INTEGER_TYPE)
> -       retval = (retval * 17) / 10;
> -    }
> -
> -  m_costs[where] += retval;
> -
> -  return retval;
> +  return stmt_cost + vector_costs::add_slp_cost (node, parts);
>  }
>
>  void
> diff --git a/gcc/tree-vect-slp.cc b/gcc/tree-vect-slp.cc
> index b8096f9256d..3e1bfd000f1 100644
> --- a/gcc/tree-vect-slp.cc
> +++ b/gcc/tree-vect-slp.cc
> @@ -9005,7 +9005,6 @@ vect_prologue_cost_for_slp (slp_tree node, unsigned 
> nvectors,
>      }
>    /* ???  We're just tracking whether vectors in a single node are the same.
>       Ideally we'd do something more global.  */
> -  bool passed = false;
>    for (unsigned int start : starts)
>      {
>        vect_cost_for_stmt kind;
> @@ -9015,15 +9014,8 @@ vect_prologue_cost_for_slp (slp_tree node, unsigned 
> nvectors,
>         kind = scalar_to_vec;
>        else
>         kind = vec_construct;
> -      /* The target cost hook has no idea which part of the SLP node
> -        we are costing so avoid passing it down more than once.  Pass
> -        it to the first vec_construct or scalar_to_vec part since for those
> -        the x86 backend tries to account for GPR to XMM register moves.  */
> -      record_stmt_cost (cost_vec, 1, kind, nullptr,
> -                       (kind != vector_load && !passed) ? node : nullptr,
> +      record_stmt_cost (cost_vec, 1, kind, nullptr, node,
>                         vectype, 0, vect_prologue);
> -      if (kind != vector_load)
> -       passed = true;
>      }
>  }
>
> @@ -9397,9 +9389,14 @@ add_slp_costs (vector_costs *costs, 
> stmt_vector_for_cost& cost_vec)
>        while (end < cost_vec.length ()
>              && cost_vec[start].node == cost_vec[end].node)
>         end++;
> -      costs->add_slp_cost (cost_vec[start].node,
> -                          array_slice<stmt_info_for_cost>
> -                            (cost_vec.begin () + start, end - start));
> +      if (cost_vec[start].node)
> +       costs->add_slp_cost (cost_vec[start].node,
> +                            array_slice<stmt_info_for_cost>
> +                              (cost_vec.begin () + start, end - start));
> +      else
> +       costs->vector_costs::add_slp_cost (cost_vec[start].node,
> +                            array_slice<stmt_info_for_cost>
> +                              (cost_vec.begin () + start, end - start));
>        start = end;
>      }
>  }
> --
> 2.51.0



-- 
BR,
Hongtao

Reply via email to