On April 8, 2020 8:14:56 PM GMT+02:00, Jakub Jelinek <ja...@redhat.com> wrote:
>Hi!
>
>The first testcase below is miscompiled, because for the division part
>of the lowering we canonicalize negative divisors to their absolute
>value
>(similarly how expmed.c canonicalizes it), but when multiplying the
>division
>result back by the VECTOR_CST, we use the original constant, which can
>contain negative divisors.
>
>Fixed by computing ABS_EXPR of the VECTOR_CST.  Unfortunately,
>fold-const.c
>doesn't support const_unop (ABS_EXPR, VECTOR_CST) and I think it is too
>late
>in GCC 10 cycle to add it now.
>
>Furthermore, while modulo by most negative constant happens to return
>the
>right value, it does that only by invoking UB in the IL, because
>we then expand division by that 1U+INT_MAX and say for INT_MIN %
>INT_MIN
>compute the division as -1, and then multiply by INT_MIN, which is
>signed
>integer overflow.  We in theory could do the computation in unsigned
>vector
>types instead, but is it worth bothering.  People that are doing %
>INT_MIN
>are either testing for standard conformance, or doing something wrong.
>So, I've also added punting on % INT_MIN, both in vect lowering and
>vect
>pattern recognition (we punt already for / INT_MIN).
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK. 

Richard 

>2020-04-08  Jakub Jelinek  <ja...@redhat.com>
>
>       PR tree-optimization/94524
>       * tree-vect-generic.c (expand_vector_divmod): If any elt of op1 is
>       negative for signed TRUNC_MOD_EXPR, multiply with absolute value of
>       op1 rather than op1 itself at the end.  Punt for signed modulo by
>       most negative constant.
>       * tree-vect-patterns.c (vect_recog_divmod_pattern): Punt for signed
>       modulo by most negative constant.
>
>       * gcc.c-torture/execute/pr94524-1.c: New test.
>       * gcc.c-torture/execute/pr94524-2.c: New test.
>
>--- gcc/tree-vect-generic.c.jj 2020-01-12 11:54:38.518381650 +0100
>+++ gcc/tree-vect-generic.c    2020-04-08 11:46:34.411988882 +0200
>@@ -478,6 +478,7 @@ expand_vector_divmod (gimple_stmt_iterat
> {
>   bool use_pow2 = true;
>   bool has_vector_shift = true;
>+  bool use_abs_op1 = false;
>   int mode = -1, this_mode;
>   int pre_shift = -1, post_shift;
>   unsigned int nunits = nunits_for_known_piecewise_op (type);
>@@ -618,8 +619,11 @@ expand_vector_divmod (gimple_stmt_iterat
> 
>         /* n rem d = n rem -d */
>         if (code == TRUNC_MOD_EXPR && d < 0)
>-          d = abs_d;
>-        else if (abs_d == HOST_WIDE_INT_1U << (prec - 1))
>+          {
>+            d = abs_d;
>+            use_abs_op1 = true;
>+          }
>+        if (abs_d == HOST_WIDE_INT_1U << (prec - 1))
>           {
>             /* This case is not handled correctly below.  */
>             mode = -2;
>@@ -899,6 +903,23 @@ expand_vector_divmod (gimple_stmt_iterat
>   if (op == unknown_optab
>       || optab_handler (op, TYPE_MODE (type)) == CODE_FOR_nothing)
>     return NULL_TREE;
>+  if (use_abs_op1)
>+    {
>+      tree_vector_builder elts;
>+      if (!elts.new_unary_operation (type, op1, false))
>+      return NULL_TREE;
>+      unsigned int count = elts.encoded_nelts ();
>+      for (unsigned int i = 0; i < count; ++i)
>+      {
>+        tree elem1 = VECTOR_CST_ELT (op1, i);
>+
>+        tree elt = const_unop (ABS_EXPR, TREE_TYPE (elem1), elem1);
>+        if (elt == NULL_TREE)
>+          return NULL_TREE;
>+        elts.quick_push (elt);
>+      }
>+      op1 = elts.build ();
>+    }
>   tem = gimplify_build2 (gsi, MULT_EXPR, type, cur_op, op1);
>   op = optab_for_tree_code (MINUS_EXPR, type, optab_default);
>   if (op == unknown_optab
>--- gcc/tree-vect-patterns.c.jj        2020-01-12 11:54:38.520381620 +0100
>+++ gcc/tree-vect-patterns.c   2020-04-08 11:47:05.540523021 +0200
>@@ -3365,8 +3365,8 @@ vect_recog_divmod_pattern (stmt_vec_info
>         d = abs_d;
>         oprnd1 = build_int_cst (itype, abs_d);
>       }
>-      else if (HOST_BITS_PER_WIDE_INT >= prec
>-             && abs_d == HOST_WIDE_INT_1U << (prec - 1))
>+      if (HOST_BITS_PER_WIDE_INT >= prec
>+        && abs_d == HOST_WIDE_INT_1U << (prec - 1))
>       /* This case is not handled correctly below.  */
>       return NULL;
> 
>--- gcc/testsuite/gcc.c-torture/execute/pr94524-1.c.jj 2020-04-08
>11:48:37.357148916 +0200
>+++ gcc/testsuite/gcc.c-torture/execute/pr94524-1.c    2020-04-08
>11:50:01.152894857 +0200
>@@ -0,0 +1,19 @@
>+/* PR tree-optimization/94524 */
>+
>+typedef signed char __attribute__ ((__vector_size__ (16))) V;
>+
>+static __attribute__ ((__noinline__, __noclone__)) V
>+foo (V c)
>+{
>+  c %= (signed char) -19;
>+  return (V) c;
>+}
>+
>+int
>+main ()
>+{
>+  V x = foo ((V) { 31 });
>+  if (x[0] != 12)
>+    __builtin_abort ();
>+  return 0;
>+}
>--- gcc/testsuite/gcc.c-torture/execute/pr94524-2.c.jj 2020-04-08
>11:48:40.694098980 +0200
>+++ gcc/testsuite/gcc.c-torture/execute/pr94524-2.c    2020-04-08
>11:50:13.049716806 +0200
>@@ -0,0 +1,25 @@
>+/* PR tree-optimization/94524 */
>+
>+typedef signed char __attribute__ ((__vector_size__ (16))) V;
>+
>+static __attribute__ ((__noinline__, __noclone__)) V
>+foo (V c)
>+{
>+  c %= (signed char) -128;
>+  return (V) c;
>+}
>+
>+int
>+main ()
>+{
>+  V x = foo ((V) { -128 });
>+  if (x[0] != 0)
>+    __builtin_abort ();
>+  x = foo ((V) { -127 });
>+  if (x[0] != -127)
>+    __builtin_abort ();
>+  x = foo ((V) { 127 });
>+  if (x[0] != 127)
>+    __builtin_abort ();
>+  return 0;
>+}
>
>       Jakub

Reply via email to