On Fri, Aug 21, 2026 at 12:28 PM <[email protected]> wrote: > > From: Kyrylo Tkachov <[email protected]> > > unsigned_integer_narrow_clip matches > > (UT) X > (NT) -1 ? (-X) >> (PREC (X) - 1) : X > > and rewrites it to SAT_U_TRUNC (MAX (0, X)). The two agree everywhere > except at the minimum of X's type, where the negation is its own > inverse. The shift then yields -1 and the expression gives NT_MAX, > while MAX (0, X) gives 0. > > The negation is on the unsigned type in the gimple the pattern was > written for, so there is no undefined behaviour to appeal to, and the > rewrite changes the result of a well defined program. Only accept the > pattern when the minimum value is known not to occur. > > void > clip (unsigned short *__restrict out, const int *__restrict in, int n) > { > for (int i = 0; i < n; ++i) > { > int x = in[i]; > out[i] = (unsigned) x > 65535u ? (int) (-(unsigned) x) >> 31 : x; > } > } > > For x == INT_MIN this stored 0 rather than 65535 on a target with a > saturating truncation optab. > > Bootstrapped and tested on aarch64-none-linux-gnu. > Ok for trunk?
OK. Richard. > Thanks, > Kyrill > > gcc/ChangeLog: > > PR tree-optimization/126981 > * match-sat-alu.pd (unsigned_integer_narrow_clip): Require the > operand to be known different from the minimum of its type. > > gcc/testsuite/ChangeLog: > > PR tree-optimization/126981 > * gcc.dg/vect/pr126981.c: New test. > > Signed-off-by: Kyrylo Tkachov <[email protected]> > --- > gcc/match-sat-alu.pd | 13 ++++++-- > gcc/testsuite/gcc.dg/vect/pr126981.c | 48 ++++++++++++++++++++++++++++ > 2 files changed, 58 insertions(+), 3 deletions(-) > create mode 100644 gcc/testsuite/gcc.dg/vect/pr126981.c > > diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd > index ede87138d49..c7333e8c211 100644 > --- a/gcc/match-sat-alu.pd > +++ b/gcc/match-sat-alu.pd > @@ -208,7 +208,11 @@ along with GCC; see the file COPYING3. If not see > (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. */ > + using & so match on gt instead of bit_and. > + > + 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) > @0)) > @@ -225,8 +229,11 @@ along with GCC; see the file COPYING3. If not see > int cmp = 0; > cmp = wi::cmp (int_cst_2, shift_amount, TYPE_SIGN (TREE_TYPE (@0))); > } > - (if (otype_precision < itype_precision && wi::eq_p (trunc_max, > - int_cst_1) && (cmp >= 0))))))) > + (if (otype_precision < itype_precision > + && wi::eq_p (trunc_max, int_cst_1) > + && cmp >= 0 > + && expr_not_equal_to (@0, wi::min_value (itype_precision, > + SIGNED)))))))) > > /* Saturation truncate for unsigned integer. */ > (if (INTEGRAL_TYPE_P (type) && TYPE_UNSIGNED (type)) > diff --git a/gcc/testsuite/gcc.dg/vect/pr126981.c > b/gcc/testsuite/gcc.dg/vect/pr126981.c > new file mode 100644 > index 00000000000..a6bdfc98ebf > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/vect/pr126981.c > @@ -0,0 +1,48 @@ > +/* PR tree-optimization/126981 */ > +/* { dg-require-effective-target vect_int } */ > + > +#include "tree-vect.h" > + > +#define N 64 > + > +/* Clip to [0, 65535]. At INT_MIN the negation is its own inverse, so the > + shift yields -1 and the result is 65535 rather than 0. */ > + > +__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]; > + out[i] = ((unsigned int) x > 65535u > + ? (int) (-(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 & 3) == 0 ? (-__INT_MAX__ - 1) : i * 12345 - 30000; > + > + clip (out, in, N); > + > +#pragma GCC novector > + for (int i = 0; i < N; ++i) > + { > + int x = in[i]; > + unsigned short ref = ((unsigned int) x > 65535u > + ? (int) (-(unsigned int) x) >> 31 > + : x); > + if (out[i] != ref) > + abort (); > + } > + > + return 0; > +} > -- > 2.50.1 (Apple Git-155) >
