On Fri, Aug 21, 2026 at 12:29 PM <[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?
OK. Richard. > 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) >
