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