> Please don't build GENERIC, do what the code did before.
> Thus, seems like you used AI for this, but I see no disclaimer?

You are right. We periodically use AI assistance to backport selected 
bug-fix patches from master to our local GCC 14 branch. The local 
version of this code had not been reviewed carefully enough and already
 differed from the original implementation.When preparing this patch, 
I based the change on that local code and only changed ops[0] to input.
I am very sorry for my carelessness.

   if (v_itype == NULL_TREE
-      || v_otype == NULL_TREE
       || !direct_internal_fn_supported_p (IFN_SAT_TRUNC,
                                          tree_pair (v_otype, v_itype),
                                          OPTIMIZE_FOR_BOTH))
     return NULL;
 
   tree temp = vect_recog_temp_ssa_var (itype, NULL);
-  tree max_op = build2 (MAX_EXPR, itype, build_zero_cst (itype), ops[0]);
+  tree max_op = build2 (MAX_EXPR, itype, build_zero_cst (itype), input);

------------------------------------------------------------------
发件人:Richard Biener <[email protected]>
发送时间:2026年8月25日(周二) 18:59
收件人:wangjue<[email protected]>
抄 送:"gcc-patches"<[email protected]>; "rdapp.gcc"<[email protected]>; 
"jeffrey.law"<[email protected]>; 
"kito.cheng"<[email protected]>; 
"wangjue.wangjue"<[email protected]>
主 题:Re: [RFC] vect: Use unpromoted inputs for unsigned narrow clips


On Tue, Aug 25, 2026 at 10:50 AM wangjue <[email protected]> wrote:
>
> From: juewang <[email protected]>
>
> The unsigned narrow-clip pattern currently builds MAX_EXPR and
> IFN_SAT_TRUNC using the promoted input type.  This can make the
> vectorizer widen an input only to narrow it again.
>
> Look through a single-use promotion when the sign is unchanged and the
> target supports SAT_TRUNC directly from the original type.  Build the
> MAX_EXPR from that input so that the operation retains the narrower
> vector element type.
>
> gcc/ChangeLog:
>
>         * tree-vect-patterns.cc (vect_recog_sat_trunc_pattern): Use an
>         unpromoted input when possible.
>
> gcc/testsuite/ChangeLog:
>
>         * gcc.target/riscv/rvv/autovec/sat/vec_sat_u_trunc-promotion-1.c:
>         New test.
> ---
>  .../autovec/sat/vec_sat_u_trunc-promotion-1.c | 28 ++++++++++++
>  gcc/tree-vect-patterns.cc                     | 45 ++++++++++++++++---
>  2 files changed, 66 insertions(+), 7 deletions(-)
>  create mode 100644 
>gcc/testsuite/gcc.target/riscv/rvv/autovec/sat/vec_sat_u_trunc-promotion-1.c
>
> diff --git 
> a/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat/vec_sat_u_trunc-promotion-1.c
>  
> b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat/vec_sat_u_trunc-promotion-1.c
> new file mode 100644
> index 00000000000..d8f40cb8e88
> --- /dev/null
> +++ 
> b/gcc/testsuite/gcc.target/riscv/rvv/autovec/sat/vec_sat_u_trunc-promotion-1.c
> @@ -0,0 +1,28 @@
> +/* { dg-do compile } */
> +/* { dg-options "-march=rv64gcv -mabi=lp64d -O3 -mrvv-max-lmul=m1 
> -fno-vect-cost-model" } */
> +
> +#include <stdint-gcc.h>
> +
> +static inline uint8_t
> +clip_uint8 (int x)
> +{
> +  return x & ~255 ? (-x) >> 31 : x;
> +}
> +
> +__attribute__ ((noipa)) void
> +hpel_clip (uint8_t *__restrict dst, const uint8_t *__restrict src, int n)
> +{
> +  for (int i = 0; i < n; ++i)
> +    {
> +      int value = (src[i - 2] + src[i + 3]
> +                  - 5 * (src[i - 1] + src[i + 2])
> +                  + 20 * (src[i] + src[i + 1]));
> +      dst[i] = clip_uint8 ((value + 16) >> 5);
> +    }
> +}
> +
> +/* { dg-final { scan-assembler-times {vnclipu\.wi} 1 } } */
> +/* { dg-final { scan-assembler {vsetvli\t[^\n]+,e8,mf2,ta,ma} } } */
> +/* { dg-final { scan-assembler {vsetvli\t[^\n]+,e16,m1,ta,ma} } } */
> +/* { dg-final { scan-assembler-not {vsext\.vf2} } } */
> +/* { dg-final { scan-assembler-not {e32,m1} } } */
> diff --git a/gcc/tree-vect-patterns.cc b/gcc/tree-vect-patterns.cc
> index b921ae94848..4865a0ded90 100644
> --- a/gcc/tree-vect-patterns.cc
> +++ b/gcc/tree-vect-patterns.cc
> @@ -4822,20 +4822,51 @@ vect_recog_sat_trunc_pattern (vec_info *vinfo, 
> stmt_vec_info stmt_vinfo,
>    tree lhs = gimple_assign_lhs (last_stmt);
>    tree otype = TREE_TYPE (lhs);
>
> -  if ((gimple_unsigned_integer_narrow_clip (lhs, ops, NULL))
> -       && type_has_mode_precision_p (otype))
> +  if (gimple_unsigned_integer_narrow_clip (lhs, ops, NULL)
> +      && type_has_mode_precision_p (otype))
>      {
> -      tree itype = TREE_TYPE (ops[0]);
> -      tree v_itype = get_vectype_for_scalar_type (vinfo, itype);
> +      tree input = ops[0];
> +      tree itype = TREE_TYPE (input);
>        tree v_otype = get_vectype_for_scalar_type (vinfo, otype);
>        internal_fn fn = IFN_SAT_TRUNC;
>
> +      /* Avoid widening an input only to narrow it again.  A signed
> +        promotion does not affect MAX (X, 0), so use the unpromoted value
> +        when the target can narrow it directly to the output type.  */
> +      vect_unpromoted_value unprom;
> +      bool single_use_p = true;
> +      if (v_otype != NULL_TREE
> +         && vect_look_through_possible_promotion (vinfo, input, &unprom,
> +                                                    &single_use_p)
> +         && single_use_p
> +         && INTEGRAL_TYPE_P (unprom.type)
> +         && TYPE_SIGN (unprom.type) == TYPE_SIGN (itype)
> +         && type_has_mode_precision_p (unprom.type)
> +         && TYPE_PRECISION (otype) < TYPE_PRECISION (unprom.type)
> +         && TYPE_PRECISION (unprom.type) < TYPE_PRECISION (itype))
> +       {
> +         tree v_unprom_type
> +           = get_vectype_for_scalar_type (vinfo, unprom.type);
> +         if (v_unprom_type != NULL_TREE
> +             && direct_internal_fn_supported_p
> +                  (fn, tree_pair (v_otype, v_unprom_type),
> +                   OPTIMIZE_FOR_BOTH))
> +           {
> +             input = unprom.op;
> +             itype = unprom.type;
> +           }
> +       }
> +
> +      tree v_itype = get_vectype_for_scalar_type (vinfo, itype);
>        if (v_itype != NULL_TREE && v_otype != NULL_TREE
> -       && direct_internal_fn_supported_p (fn, tree_pair (v_otype, v_itype),
> -                                          OPTIMIZE_FOR_BOTH))
> +         && direct_internal_fn_supported_p (fn,
> +                                            tree_pair (v_otype, v_itype),
> +                                            OPTIMIZE_FOR_BOTH))
>         {
>           tree temp = vect_recog_temp_ssa_var (itype, NULL);
> -         gimple * max_stmt = gimple_build_assign (temp, build2 (MAX_EXPR, 
> itype, build_zero_cst(itype), ops[0]));
> +         tree max_op = build2 (MAX_EXPR, itype, build_zero_cst (itype),
> +                       input);
> +         gimple *max_stmt = gimple_build_assign (temp, max_op);

Please don't build GENERIC, do what the code did before.
Thus, seems like you used AI for this, but I see no disclaimer?

Thanks,
Richard.

>           append_pattern_def_seq (vinfo, stmt_vinfo, max_stmt, v_itype);
>
>           gcall *call = gimple_build_call_internal (fn, 1, temp);
> --
> 2.34.1
>

Reply via email to