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