Hi!

The op1 - op2 line instead of multiplication is something that has been
introduced in C++ double_int changes, but without the 2 * TYPE_PRECISION
prec it would always return 0 or -1 anyway.  And, with wide_mul_with_sign
we can also handle 2 * HOST_BITS_PER_WIDE_INT precisions.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk/4.8?

2013-04-11  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/56918
        PR tree-optimization/56920
        * fold-const.c (int_const_binop_1): Use op1.mul_with_sign (op2, ...)
        instead of op1 - op2.  Pass 2 * TYPE_PRECISION (type) as second
        argument to rshift method.  For 2 * HOST_BITS_PER_WIDE_INT precision
        use wide_mul_with_sign method.

        * gcc.dg/vect/pr56918.c: New test.
        * gcc.dg/vect/pr56920.c: New test.

--- gcc/fold-const.c.jj 2013-04-11 09:36:41.000000000 +0200
+++ gcc/fold-const.c    2013-04-11 16:16:50.273545925 +0200
@@ -984,12 +984,16 @@ int_const_binop_1 (enum tree_code code,
       break;
 
     case MULT_HIGHPART_EXPR:
-      /* ??? Need quad precision, or an additional shift operand
-        to the multiply primitive, to handle very large highparts.  */
       if (TYPE_PRECISION (type) > HOST_BITS_PER_WIDE_INT)
-       return NULL_TREE;
-      tmp = op1 - op2;
-      res = tmp.rshift (TYPE_PRECISION (type), TYPE_PRECISION (type), !uns);
+       {
+         if (TYPE_PRECISION (type) != 2 * HOST_BITS_PER_WIDE_INT)
+           return NULL_TREE;
+         op1.wide_mul_with_sign (op2, false, &res, &overflow);
+         break;
+       }
+      tmp = op1.mul_with_sign (op2, false, &overflow);
+      res
+       = tmp.rshift (TYPE_PRECISION (type), 2 * TYPE_PRECISION (type), !uns);
       break;
 
     case TRUNC_DIV_EXPR:
--- gcc/testsuite/gcc.dg/vect/pr56918.c.jj      2013-04-11 16:26:36.269168125 
+0200
+++ gcc/testsuite/gcc.dg/vect/pr56918.c 2013-04-11 16:30:07.410945804 +0200
@@ -0,0 +1,31 @@
+/* PR tree-optimization/56918 */
+/* { dg-additional-options "-O3" } */
+
+#include "tree-vect.h"
+
+extern void abort (void);
+double data[8];
+
+__attribute__((noinline, noclone)) void
+foo ()
+{
+  int i;
+  for (i = 0; i < 8; ++i)
+    data[i] = ((i + 2) % 3) + 1;
+}
+
+int
+main ()
+{
+  int i;
+  check_vect ();
+  foo ();
+  if (data[0] != 3 || data[7] != 1)
+    abort ();
+  for (i = 1; i < 4; ++i)
+    if (data[i] != i || data[i + 3] != i)
+      abort ();
+  return 0;
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */
--- gcc/testsuite/gcc.dg/vect/pr56920.c.jj      2013-04-11 17:16:48.570982675 
+0200
+++ gcc/testsuite/gcc.dg/vect/pr56920.c 2013-04-11 17:17:28.310757853 +0200
@@ -0,0 +1,21 @@
+/* PR tree-optimization/56920 */
+/* { dg-additional-options "-O3" } */
+
+#include "tree-vect.h"
+
+extern void abort (void);
+
+int
+main ()
+{
+  unsigned int a[15], i;
+  check_vect ();
+  for (i = 0; i < 15; ++i)
+    a[i] = (i * 2) % 15;
+  for (i = 0; i < 15; ++i)
+    if (a[i] != (i * 2) % 15)
+      abort ();
+  return 0;
+}
+
+/* { dg-final { cleanup-tree-dump "vect" } } */

        Jakub

Reply via email to