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


Thanks,
Kyrill

> On 21 Aug 2026, at 12:27, Kyrylo Tkachov <[email protected]> wrote:
> 
> From: Kyrylo Tkachov <[email protected]>
> 
> signed_integer_sat_trunc builds the constants of
> 
>  (unsigned) X + NT_MAX + 1 > UNSIGNED_MAX ? saturate : (NT) X
> 
> at the precision of X, but the captured constants belong to the type of
> the conversion, which the match never constrains.  A variable shift
> leaves the shift result in int and the comparison narrows it, so the two
> precisions differ and wi::eq_p asserts:
> 
>  during GIMPLE pass: vect
>  internal compiler error: in decompose, at wide-int.h:1049
>    gimple_signed_integer_sat_trunc
>    vect_recog_sat_trunc_pattern
> 
> Require the conversion to keep the precision of X.  A narrowing
> conversion compares only the low bits of X, so the expression is not a
> saturating truncation of X.  Nothing that used to be matched is lost,
> because any case whose precisions differed hit the assert rather than
> reaching a result.  Also require the result to be narrower than X, which
> is what makes the widths of the masks below valid.
> 
> Bootstrapped and tested on aarch64-none-linux-gnu.
> Ok for trunk?
> Thanks,
> Kyrill
> 
> gcc/ChangeLog:
> 
> PR tree-optimization/126982
> * match-sat-alu.pd (signed_integer_sat_trunc): Require the
> conversion to keep the precision of the operand, and the result
> to be narrower than it.
> 
> gcc/testsuite/ChangeLog:
> 
> PR tree-optimization/126982
> * gcc.dg/vect/pr126982.c: New test.
> 
> Signed-off-by: Kyrylo Tkachov <[email protected]>
> ---
> gcc/match-sat-alu.pd                 |  7 +++-
> gcc/testsuite/gcc.dg/vect/pr126982.c | 53 ++++++++++++++++++++++++++++
> 2 files changed, 59 insertions(+), 1 deletion(-)
> create mode 100644 gcc/testsuite/gcc.dg/vect/pr126982.c
> 
> diff --git a/gcc/match-sat-alu.pd b/gcc/match-sat-alu.pd
> index c7333e8c211..7bbe2bbb26e 100644
> --- a/gcc/match-sat-alu.pd
> +++ b/gcc/match-sat-alu.pd
> @@ -434,7 +434,12 @@ along with GCC; see the file COPYING3.  If not see
>     (negate (nop_convert? (convert (lt @0 integer_zerop)))))
>    INTEGER_CST@3)
> (convert @0))
> -  (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@4)))
> +  /* The comparison has to be the unsigned reinterpretation of X, and the
> +     conversion has to narrow, otherwise the constants below do not have the
> +     precision the comparison is carried out at.  */
> +  (if (!TYPE_UNSIGNED (TREE_TYPE (@0)) && TYPE_UNSIGNED (TREE_TYPE (@4))
> +       && TYPE_PRECISION (TREE_TYPE (@4)) == TYPE_PRECISION (TREE_TYPE (@0))
> +       && TYPE_PRECISION (type) < TYPE_PRECISION (TREE_TYPE (@0)))
>    (with
>     {
>      unsigned itype_prec = TYPE_PRECISION (TREE_TYPE (@0));
> diff --git a/gcc/testsuite/gcc.dg/vect/pr126982.c 
> b/gcc/testsuite/gcc.dg/vect/pr126982.c
> new file mode 100644
> index 00000000000..384df709c8a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/vect/pr126982.c
> @@ -0,0 +1,53 @@
> +/* PR tree-optimization/126982 */
> +/* { dg-require-effective-target vect_int } */
> +
> +#include "tree-vect.h"
> +
> +#define N 64
> +
> +/* A variable shift keeps the shift result in int, so the comparison of the
> +   saturating truncation runs at a narrower precision than the value being
> +   truncated.  The comparison then only looks at the low bits, and the
> +   truncation is not a saturating one.  */
> +
> +__attribute__ ((noipa)) void
> +sat_trunc (signed char *__restrict out, const short *__restrict in,
> +   const unsigned short *__restrict shifts, int n)
> +{
> +  for (int i = 0; i < n; ++i)
> +    {
> +      short x = in[i] >> (shifts[i] & 15);
> +      signed char t = (signed char) x;
> +      out[i] = (-128 <= x && x <= 127 ? t : x < 0 ? -128 : 127);
> +    }
> +}
> +
> +int
> +main (void)
> +{
> +  short in[N];
> +  unsigned short shifts[N];
> +  signed char out[N];
> +
> +  check_vect ();
> +
> +  for (int i = 0; i < N; ++i)
> +    {
> +      in[i] = (short) (i * 7919 - 32768);
> +      shifts[i] = i % 16;
> +    }
> +
> +  sat_trunc (out, in, shifts, N);
> +
> +#pragma GCC novector
> +  for (int i = 0; i < N; ++i)
> +    {
> +      short x = in[i] >> (shifts[i] & 15);
> +      signed char t = (signed char) x;
> +      signed char ref = (-128 <= x && x <= 127 ? t : x < 0 ? -128 : 127);
> +      if (out[i] != ref)
> + abort ();
> +    }
> +
> +  return 0;
> +}
> -- 
> 2.50.1 (Apple Git-155)
> 

Reply via email to