diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 41dcb5d6ca5..40ef344df18 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,13 @@ +2016-11-28 Jakub Jelinek + + PR rtl-optimization/78546 + * simplify-rtx.c (neg_const_int): When negating most negative + number in mode wider than HOST_BITS_PER_WIDE_INT, use + simplify_const_unary_operation to produce CONST_DOUBLE or + CONST_WIDE_INT. + (simplify_plus_minus): Hanlde the case where neg_const_int + doesn't return a CONST_INT. + 2016-11-28 Markus Trippelsdorf PR target/78556 diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index f6131d48130..83fb37d8535 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -56,12 +56,17 @@ static rtx simplify_unary_operation_1 (enum rtx_code, machine_mode, rtx); static rtx simplify_binary_operation_1 (enum rtx_code, machine_mode, rtx, rtx, rtx, rtx); -/* Negate a CONST_INT rtx, truncating (because a conversion from a - maximally negative number can overflow). */ +/* Negate a CONST_INT rtx. */ static rtx neg_const_int (machine_mode mode, const_rtx i) { - return gen_int_mode (-(unsigned HOST_WIDE_INT) INTVAL (i), mode); + unsigned HOST_WIDE_INT val = -UINTVAL (i); + + if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT + && val == UINTVAL (i)) + return simplify_const_unary_operation (NEG, mode, CONST_CAST_RTX (i), + mode); + return gen_int_mode (val, mode); } /* Test whether expression, X, is an immediate constant that represents @@ -4507,9 +4512,12 @@ simplify_plus_minus (enum rtx_code code, machine_mode mode, rtx op0, rtx value = ops[n_ops - 1].op; if (ops[n_ops - 1].neg ^ ops[n_ops - 2].neg) value = neg_const_int (mode, value); - ops[n_ops - 2].op = plus_constant (mode, ops[n_ops - 2].op, - INTVAL (value)); - n_ops--; + if (CONST_INT_P (value)) + { + ops[n_ops - 2].op = plus_constant (mode, ops[n_ops - 2].op, + INTVAL (value)); + n_ops--; + } } /* Put a non-negated operand first, if possible. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 48ccdd969bb..04a6840299d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,9 @@ 2016-11-28 Jakub Jelinek + PR rtl-optimization/78546 + * gcc.dg/torture/pr78546-1.c: New test. + * gcc.dg/torture/pr78546-2.c: New test. + PR fortran/78298 * gfortran.dg/gomp/pr78298.f90: New test. diff --git a/gcc/testsuite/gcc.dg/torture/pr78546-1.c b/gcc/testsuite/gcc.dg/torture/pr78546-1.c new file mode 100644 index 00000000000..9cae5b18858 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr78546-1.c @@ -0,0 +1,22 @@ +/* PR rtl-optimization/78546 */ +/* { dg-do run { target int128 } } */ + +typedef unsigned __int128 u128; +u128 b; + +static inline u128 +foo (u128 p1) +{ + p1 += ~b; + return -p1; +} + +int +main () +{ + asm volatile ("" : : : "memory"); + u128 x = foo (~0x7fffffffffffffffLL); + if (x != 0x8000000000000001ULL) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/gcc.dg/torture/pr78546-2.c b/gcc/testsuite/gcc.dg/torture/pr78546-2.c new file mode 100644 index 00000000000..afec5b5bfc8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr78546-2.c @@ -0,0 +1,16 @@ +/* PR rtl-optimization/78546 */ +/* { dg-do run { target int128 } } */ + +typedef unsigned __int128 u128; +u128 b; + +int +main () +{ + asm volatile ("" : : : "memory"); + u128 x = ((u128) ~0x7fffffffffffffffLL) - b; + u128 y = 1 - x; + if (y != 0x8000000000000001ULL) + __builtin_abort (); + return 0; +}