The following fixes fold_binary to not call negate_expr_p on arg[01] as those have sign-changing nops stripped which gets us wrong answers for negate_expr_p. Instead of passing arg[01] we need to pass op[01] (negate_expr_p and friends use STRIP_SIGN_NOPS themselves).
Bootstrapped and tested on x86_64-unknown-linux-gnu, applied to trunk. Richard. 2015-11-25 Richard Biener <rguent...@suse.de> PR middle-end/68528 * fold-const.c (fold_binary_loc): Do not call negate_expr_p on stripped operands. * gcc.dg/torture/pr68528.c: New testcase. Index: gcc/fold-const.c =================================================================== *** gcc/fold-const.c (revision 230857) --- gcc/fold-const.c (working copy) *************** fold_binary_loc (location_t loc, *** 9681,9693 **** case MINUS_EXPR: /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ if (TREE_CODE (arg0) == NEGATE_EXPR ! && negate_expr_p (arg1) && reorder_operands_p (arg0, arg1)) return fold_build2_loc (loc, MINUS_EXPR, type, ! fold_convert_loc (loc, type, ! negate_expr (arg1)), ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg0, 0))); /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to __complex__ ( x, -y ). This is not the same for SNaNs or if --- 9681,9692 ---- case MINUS_EXPR: /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ if (TREE_CODE (arg0) == NEGATE_EXPR ! && negate_expr_p (op1) && reorder_operands_p (arg0, arg1)) return fold_build2_loc (loc, MINUS_EXPR, type, ! negate_expr (op1), ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg0, 0))); /* Fold __complex__ ( x, 0 ) - __complex__ ( 0, y ) to __complex__ ( x, -y ). This is not the same for SNaNs or if *************** fold_binary_loc (location_t loc, *** 9727,9743 **** } /* A - B -> A + (-B) if B is easily negatable. */ ! if (negate_expr_p (arg1) ! && !TYPE_OVERFLOW_SANITIZED (type) && ((FLOAT_TYPE_P (type) /* Avoid this transformation if B is a positive REAL_CST. */ ! && (TREE_CODE (arg1) != REAL_CST ! || REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))) || INTEGRAL_TYPE_P (type))) return fold_build2_loc (loc, PLUS_EXPR, type, ! fold_convert_loc (loc, type, arg0), ! fold_convert_loc (loc, type, ! negate_expr (arg1))); /* Fold &a[i] - &a[j] to i-j. */ if (TREE_CODE (arg0) == ADDR_EXPR --- 9726,9741 ---- } /* A - B -> A + (-B) if B is easily negatable. */ ! if (negate_expr_p (op1) ! && ! TYPE_OVERFLOW_SANITIZED (type) && ((FLOAT_TYPE_P (type) /* Avoid this transformation if B is a positive REAL_CST. */ ! && (TREE_CODE (op1) != REAL_CST ! || REAL_VALUE_NEGATIVE (TREE_REAL_CST (op1)))) || INTEGRAL_TYPE_P (type))) return fold_build2_loc (loc, PLUS_EXPR, type, ! fold_convert_loc (loc, type, arg0), ! negate_expr (op1)); /* Fold &a[i] - &a[j] to i-j. */ if (TREE_CODE (arg0) == ADDR_EXPR *************** fold_binary_loc (location_t loc, *** 9781,9795 **** if (! FLOAT_TYPE_P (type)) { /* Transform x * -C into -x * C if x is easily negatable. */ ! if (TREE_CODE (arg1) == INTEGER_CST ! && tree_int_cst_sgn (arg1) == -1 ! && negate_expr_p (arg0) ! && (tem = negate_expr (arg1)) != arg1 ! && !TREE_OVERFLOW (tem)) return fold_build2_loc (loc, MULT_EXPR, type, ! fold_convert_loc (loc, type, ! negate_expr (arg0)), ! tem); /* (A + A) * C -> A * 2 * C */ if (TREE_CODE (arg0) == PLUS_EXPR --- 9779,9792 ---- if (! FLOAT_TYPE_P (type)) { /* Transform x * -C into -x * C if x is easily negatable. */ ! if (TREE_CODE (op1) == INTEGER_CST ! && tree_int_cst_sgn (op1) == -1 ! && negate_expr_p (op0) ! && (tem = negate_expr (op1)) != op1 ! && ! TREE_OVERFLOW (tem)) return fold_build2_loc (loc, MULT_EXPR, type, ! fold_convert_loc (loc, type, ! negate_expr (op0)), tem); /* (A + A) * C -> A * 2 * C */ if (TREE_CODE (arg0) == PLUS_EXPR *************** fold_binary_loc (location_t loc, *** 10259,10265 **** undefined. */ if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg0) == NEGATE_EXPR ! && negate_expr_p (arg1)) { if (INTEGRAL_TYPE_P (type)) fold_overflow_warning (("assuming signed overflow does not occur " --- 10256,10262 ---- undefined. */ if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg0) == NEGATE_EXPR ! && negate_expr_p (op1)) { if (INTEGRAL_TYPE_P (type)) fold_overflow_warning (("assuming signed overflow does not occur " *************** fold_binary_loc (location_t loc, *** 10267,10280 **** "division"), WARN_STRICT_OVERFLOW_MISC); return fold_build2_loc (loc, code, type, ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg0, 0)), ! fold_convert_loc (loc, type, ! negate_expr (arg1))); } if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg1) == NEGATE_EXPR ! && negate_expr_p (arg0)) { if (INTEGRAL_TYPE_P (type)) fold_overflow_warning (("assuming signed overflow does not occur " --- 10264,10276 ---- "division"), WARN_STRICT_OVERFLOW_MISC); return fold_build2_loc (loc, code, type, ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg0, 0)), ! negate_expr (op1)); } if ((!INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_UNDEFINED (type)) && TREE_CODE (arg1) == NEGATE_EXPR ! && negate_expr_p (op0)) { if (INTEGRAL_TYPE_P (type)) fold_overflow_warning (("assuming signed overflow does not occur " *************** fold_binary_loc (location_t loc, *** 10282,10291 **** "division"), WARN_STRICT_OVERFLOW_MISC); return fold_build2_loc (loc, code, type, ! fold_convert_loc (loc, type, ! negate_expr (arg0)), ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg1, 0))); } /* If arg0 is a multiple of arg1, then rewrite to the fastest div --- 10278,10286 ---- "division"), WARN_STRICT_OVERFLOW_MISC); return fold_build2_loc (loc, code, type, ! negate_expr (op0), ! fold_convert_loc (loc, type, ! TREE_OPERAND (arg1, 0))); } /* If arg0 is a multiple of arg1, then rewrite to the fastest div Index: gcc/testsuite/gcc.dg/torture/pr68528.c =================================================================== *** gcc/testsuite/gcc.dg/torture/pr68528.c (revision 0) --- gcc/testsuite/gcc.dg/torture/pr68528.c (working copy) *************** *** 0 **** --- 1,17 ---- + /* { dg-do run } */ + + #define INT_MIN ( -__INT_MAX__ - 1 ) + + extern void abort (void); + + int main (void) + { + int x0 = INT_MIN; + long x1 = 0L; + int x2 = 0; + int t = ( 0 || ( INT_MIN - (int) ( x0 - x1 ) ) ); + + if ( t != 0 ) { x2 = t; abort(); } + + return 0; + }