On Tue, Sep 1, 2026 at 7:53 AM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > The unsigned_integer_narrow_clip pattern assumes that its comparison > is unsigned and its right shift is signed. nop_convert? does not > require an unsigned conversion. The :s suffix marks a single-use > value rather than a signed type.
This sounds like LLM produced, nobody would think :s marks a signed type. > > A signed comparison can preserve negative inputs. An unsigned right > shift produces zero or one instead of the all-ones clip value. Capture > both expressions and check their result types before applying the > transform. > > The tests cover each rejected form. The unsigned-shift test constrains > the input range so that the existing INT_MIN guard does not reject it > first. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk? Otherwise OK. Richard. > Thanks, > Kyrill > > gcc/ChangeLog: > > * match-sat-alu.pd (unsigned_integer_narrow_clip): Require an > unsigned comparison and a signed right shift. > > gcc/testsuite/ChangeLog: > > * gcc.dg/vect/pr127166-2.c: New test. > * gcc.target/riscv/rvv/autovec/pr127166.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match-sat-alu.pd | 13 +++-- > gcc/testsuite/gcc.dg/vect/pr127166-2.c | 44 +++++++++++++++ > .../gcc.target/riscv/rvv/autovec/pr127166.c | 53 +++++++++++++++++++ > 3 files changed, 105 insertions(+), 5 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/vect/pr127166-2.c > create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c > > diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd > index 7bbe2bbb26e..22855726d90 100644 > --- a/gcc/match-sat-alu.pd > +++ b/gcc/match-sat-alu.pd > @@ -207,16 +207,19 @@ along with GCC; see the file COPYING3. If not see > /* SAT_U_TRUNC<NT>(MAX (0, X)) = > (UT)X & ~(NT)(-1) ? (-X) >> TYPE_PRECISION(X) - 1 : X > > - The gimple representation uses X > ~(NT)(-1) instead of > - using & so match on gt instead of bit_and. > + The gimple representation uses an unsigned X > ~(NT)(-1) instead of > + using & so match on gt instead of bit_and. The right shift must be > + signed so that it produces -1 for values above NT_MAX. > > The two sides only agree when X is not the minimum of its type. At > that value the negation is its own inverse, so the shift yields -1 > and the expression gives NT_MAX where MAX (0, X) gives 0. */ > - (convert (cond^ (gt (nop_convert? @0) INTEGER_CST@1) > - (rshift:s (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2) > + (convert (cond^ (gt (nop_convert?@3 @0) INTEGER_CST@1) > + (rshift:s@4 (nop_convert? (negate (nop_convert? @0))) INTEGER_CST@2) > @0)) > - (if (! TYPE_UNSIGNED (TREE_TYPE (@0))) > + (if (! TYPE_UNSIGNED (TREE_TYPE (@0)) > + && TYPE_UNSIGNED (TREE_TYPE (@3)) > + && ! TYPE_UNSIGNED (TREE_TYPE (@4))) > (with > { > unsigned itype_precision = TYPE_PRECISION (TREE_TYPE (@0)); > diff --git a/gcc/testsuite/gcc.dg/vect/pr127166-2.c > b/gcc/testsuite/gcc.dg/vect/pr127166-2.c > new file mode 100644 > index 00000000000..9e48c44d06e > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/pr127166-2.c > @@ -0,0 +1,44 @@ > +/* PR tree-optimization/127166 */ > +/* { dg-require-effective-target int32 } */ > +/* { dg-require-effective-target vect_int } */ > + > +#include "tree-vect.h" > + > +#define N 64 > + > +__attribute__ ((noipa)) void > +clip (unsigned short *__restrict out, const int *__restrict in, int n) > +{ > + for (int i = 0; i < n; ++i) > + { > + int x = in[i] & __INT_MAX__; > + out[i] = ((unsigned int) x > 65535u > + ? (unsigned int) (-x) >> 31 : x); > + } > +} > + > +int > +main (void) > +{ > + int in[N]; > + unsigned short out[N]; > + > + check_vect (); > + > + for (int i = 0; i < N; ++i) > + in[i] = (i & 1) ? -1 : 70000 + i; > + > + clip (out, in, N); > + > +#pragma GCC novector > + for (int i = 0; i < N; ++i) > + { > + if (out[i] != 1) > + abort (); > + } > + > + return 0; > +} > + > +/* The unsigned right shift does not produce the all-ones clip value. */ > +/* { dg-final { scan-tree-dump-not "\\.SAT_TRUNC" "vect" } } */ > diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c > b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c > new file mode 100644 > index 00000000000..30a43ad64ed > --- /dev/null > +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/pr127166.c > @@ -0,0 +1,53 @@ > +/* PR tree-optimization/127166 */ > +/* { dg-do compile } */ > +/* { dg-options "-march=rv64gcv -mabi=lp64d -O2 -fgimple" } */ > +/* { dg-additional-options "-fdump-tree-vect-details" } */ > + > +void __GIMPLE (ssa, startwith ("fix_loops")) > +clip_signed_compare (unsigned short *out, const int *in) > +{ > + int i; > + int raw; > + int x; > + int neg; > + int shifted; > + int selected; > + unsigned short narrowed; > + _Bool cmp; > + const int *pin; > + const int *next_pin; > + unsigned short *pout; > + unsigned short *next_pout; > + > +__BB(2): > + goto __BB3; > + > +__BB(3): > + i_1 = __PHI (__BB2: 0, __BB4: i_2); > + pin_3 = __PHI (__BB2: in_4(D), __BB4: next_pin_5); > + pout_6 = __PHI (__BB2: out_7(D), __BB4: next_pout_8); > + raw_15 = __MEM <const int> (pin_3); > + x_9 = raw_15 | 1; > + cmp_10 = x_9 > 65535; > + neg_11 = -x_9; > + shifted_12 = neg_11 >> 31; > + selected_13 = cmp_10 ? shifted_12 : x_9; > + narrowed_14 = (unsigned short) selected_13; > + __MEM <unsigned short> (pout_6) = narrowed_14; > + next_pin_5 = pin_3 + 4ul; > + next_pout_8 = pout_6 + 2ul; > + i_2 = i_1 + 1; > + if (i_2 != 64) > + goto __BB4; > + else > + goto __BB5; > + > +__BB(4): > + goto __BB3; > + > +__BB(5): > + return; > +} > + > +/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */ > +/* { dg-final { scan-tree-dump-not "\\.SAT_TRUNC" "vect" } } */ > -- > 2.50.1 (Apple Git-155) >
