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