https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81281
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- So it is indeed the /* (T)(P + A) - (T)(P + B) -> (T)A - (T)B */ (for add (plus pointer_plus) (simplify (minus (convert (add @@0 @1)) (convert (add @0 @2))) (if (element_precision (type) <= element_precision (TREE_TYPE (@1)) /* For integer types, if A has a smaller type than T the result depends on the possible overflow in P + A. E.g. T=size_t, A=(unsigned)429497295, P>0. However, if an overflow in P + A would cause undefined behavior, we can assume that there is no overflow. */ || (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))) /* For pointer types, if the conversion of A to the final type requires a sign- or zero-extension, then we have to punt - it is not defined which one is correct. */ || (POINTER_TYPE_P (TREE_TYPE (@0)) && TREE_CODE (@1) == INTEGER_CST && tree_int_cst_sign_bit (@1) == 0 && TREE_CODE (@2) == INTEGER_CST && tree_int_cst_sign_bit (@2) == 0)) (minus (convert @1) (convert @2))))))) case, where we have: op0 (int) ((((unsigned int) ll - (unsigned int) ci) - (unsigned int) i) + 2270794745) op1 (int) ((((unsigned int) ll - (unsigned int) ci) - (unsigned int) i) + (unsigned int) ci); type here is int, @0/@1/@2 all have unsigned type. The (T)(P + A) - (T)(P + B) to (T)A - (T)B transformation is incorrect if TYPE_OVERFLOW_UNDEFINED (type) (or its element type) and either !TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0)) (or its element type), or TREE_TYPE (@1) has larger element precision. Say if T is int, and TREE_TYPE (P) is unsigned, then e.g. random example of A = 0U+INT_MIN, B = 1U, P = -1U overflows only in the (int) INT_MIN - (int) 1 case, but doesn't overflow in the (int)(-1U+INT_MIN) - (int)(1U + -1U) case (many other examples). We need to do the subtraction in an unsigned_type_for (type) instead and only cast to type at the end. For the POINTER_PLUS_EXPR case, the explicitly enabled case is only if both @1 and @2 are INTEGER_CSTs with MSB clear which is fine for the widening conversion to type, but for equal or narrowing one not really sure.