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)
>

Reply via email to