Ping.

https://gcc.gnu.org/pipermail/gcc-patches/2026-August/728434.html

Thanks,
Kyrill

> On 21 Aug 2026, at 12:26, Kyrylo Tkachov <[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?
> 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