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

Reply via email to