Hi! As the following testcase shows, the (-A) - B -> (-B) - A optimization can't be done the way it is if the negation of A is performed in type with wrapping behavior while the subtraction is done in signed type (with the same precision), as if A is (unsigned) INT_MIN, then (int) -(unsigned) INT_MIN is INT_MIN and INT_MIN - B is different from (-B) - INT_MIN. The reason we can see this is because we check that arg0 is NEGATE_EXPR, but arg0 is STRIP_NOPS from op0. If the NEGATE_EXPR is already done in signed type, then it would be already UB if A was INT_MIN and so we can safely do it.
Whether we perform the subtraction in the unsigned type or just don't optimize I think doesn't matter that much, at least the only spot during x86_64-linux and i686-linux bootstraps/regtests this new condition triggered was the new testcase, nothing else. So if you instead prefer to punt, I can tweak the patch, move the negated condition to the if above it. Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? 2017-12-14 Jakub Jelinek <ja...@redhat.com> PR tree-optimization/83269 * fold-const.c (fold_binary_loc): Perform (-A) - B -> (-B) - A subtraction in arg0's type if type is signed and arg0 is unsigned. Formatting fix. * gcc.c-torture/execute/pr83269.c: New test. --- gcc/fold-const.c.jj 2017-12-08 00:50:27.000000000 +0100 +++ gcc/fold-const.c 2017-12-14 17:42:31.221398170 +0100 @@ -9098,8 +9098,8 @@ expr_not_equal_to (tree t, const wide_in return NULL_TREE. */ tree -fold_binary_loc (location_t loc, - enum tree_code code, tree type, tree op0, tree op1) +fold_binary_loc (location_t loc, enum tree_code code, tree type, + tree op0, tree op1) { enum tree_code_class kind = TREE_CODE_CLASS (code); tree arg0, arg1, tem; @@ -9770,10 +9770,34 @@ fold_binary_loc (location_t loc, /* (-A) - B -> (-B) - A where B is easily negated and we can swap. */ if (TREE_CODE (arg0) == NEGATE_EXPR && negate_expr_p (op1)) - return fold_build2_loc (loc, MINUS_EXPR, type, - negate_expr (op1), - fold_convert_loc (loc, type, - TREE_OPERAND (arg0, 0))); + { + /* If arg0 is e.g. unsigned int and type is int, then we need to + perform the subtraction in arg0's type, because if A is + INT_MIN at runtime, the original expression can be well defined + while the latter is not. See PR83269. */ + if (ANY_INTEGRAL_TYPE_P (type) + && TYPE_OVERFLOW_UNDEFINED (type) + && ANY_INTEGRAL_TYPE_P (TREE_TYPE (arg0)) + && !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg0))) + { + /* Don't do this when sanitizing, as by doing the subtraction + in unsigned type we won't notice if the original program + has been buggy. */ + if (!TYPE_OVERFLOW_SANITIZED (type)) + { + tem = fold_build2_loc (loc, MINUS_EXPR, TREE_TYPE (arg0), + fold_convert_loc (loc, + TREE_TYPE (arg0), + negate_expr (op1)), + TREE_OPERAND (arg0, 0)); + return fold_convert_loc (loc, type, tem); + } + } + else + 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 --- gcc/testsuite/gcc.c-torture/execute/pr83269.c.jj 2017-12-14 17:43:24.534710997 +0100 +++ gcc/testsuite/gcc.c-torture/execute/pr83269.c 2017-12-14 17:43:10.000000000 +0100 @@ -0,0 +1,14 @@ +/* PR tree-optimization/83269 */ + +int +main () +{ +#if __SIZEOF_INT__ == 4 && __SIZEOF_LONG_LONG__ > 4 && __CHAR_BIT__ == 8 + volatile unsigned char a = 1; + long long b = 0x80000000L; + int c = -((int)(-b) - (-0x7fffffff * a)); + if (c != 1) + __builtin_abort (); +#endif + return 0; +} Jakub