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