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 >
