Index: match.pd =================================================================== --- match.pd (revision 248312) +++ match.pd (working copy) @@ -1265,29 +1265,53 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (simplify (minus @0 (plus:c @0 @1)) (negate @1)) (simplify (minus @0 (minus @0 @1)) @1) /* (A +- CST1) +- CST2 -> A + CST3 */ (for outer_op (plus minus) (for inner_op (plus minus) + neg_inner_op (minus plus) (simplify - (outer_op (inner_op @0 CONSTANT_CLASS_P@1) CONSTANT_CLASS_P@2) - /* If the constant operation overflows we cannot do the transform - as we would introduce undefined overflow, for example - with (a - 1) + INT_MIN. */ - (with { tree cst = const_binop (outer_op == inner_op - ? PLUS_EXPR : MINUS_EXPR, type, @1, @2); } - (if (cst && !TREE_OVERFLOW (cst)) - (inner_op @0 { cst; } )))))) + (outer_op (convert? (inner_op @0 CONSTANT_CLASS_P@1)) CONSTANT_CLASS_P@2) + (if (tree_nop_conversion_p (type, TREE_TYPE (@0))) + /* If one of the types wraps, use that one. */ + (if (!ANY_INTEGRAL_TYPE_P (type) || TYPE_OVERFLOW_WRAPS (type)) + (if (outer_op == PLUS_EXPR) + (plus (convert @0) (inner_op @2 (convert @1))) + (minus (convert @0) (neg_inner_op @2 (convert @1)))) + (if (!ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0)) + || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) + (if (outer_op == PLUS_EXPR) + (convert (plus @0 (inner_op (convert @2) @1))) + (convert (minus @0 (neg_inner_op (convert @2) @1)))) + /* If the constant operation overflows we cannot do the transform + directly as we would introduce undefined overflow, for example + with (a - 1) + INT_MIN. */ + (if (types_match (type, @0)) + (with { tree cst = const_binop (outer_op == inner_op + ? PLUS_EXPR : MINUS_EXPR, + type, @1, @2); } + (if (cst && !TREE_OVERFLOW (cst)) + (inner_op @0 { cst; } ) + /* X+INT_MAX+1 is X-INT_MIN. */ + (if (INTEGRAL_TYPE_P (type) && cst + && wi::eq_p (cst, wi::min_value (type))) + (neg_inner_op @0 { wide_int_to_tree (type, cst); }) + /* Last resort, use some unsigned type. */ + (with { tree utype = unsigned_type_for (type); } + (convert (inner_op + (convert:utype @0) + (convert:utype + { drop_tree_overflow (cst); })))))))))))))) /* (CST1 - A) +- CST2 -> CST3 - A */ (for outer_op (plus minus) (simplify (outer_op (minus CONSTANT_CLASS_P@1 @0) CONSTANT_CLASS_P@2) (with { tree cst = const_binop (outer_op, type, @1, @2); } (if (cst && !TREE_OVERFLOW (cst)) (minus { cst; } @0))))) /* CST1 - (CST2 - A) -> CST3 + A */ Index: testsuite/gcc.dg/tree-ssa/addadd.c =================================================================== --- testsuite/gcc.dg/tree-ssa/addadd.c (nonexistent) +++ testsuite/gcc.dg/tree-ssa/addadd.c (working copy) @@ -0,0 +1,34 @@ +/* { dg-do compile } */ +/* { dg-options "-O -fdump-tree-optimized" } */ + +int f(unsigned x){ + x += 123; + int y = x; + y -= 99; + return y; +} +unsigned g(int x){ + x += 123; + unsigned y = x; + y -= 99; + return y; +} +int h(int x){ + x += __INT_MAX__; + x += 1; + return x; +} +int i(int x){ + x += __INT_MAX__; + x += __INT_MAX__; + return x; +} +typedef int S __attribute__((vector_size(16))); +void j(S*x){ + *x += __INT_MAX__; + *x += __INT_MAX__; +} + +/* { dg-final { scan-tree-dump-times " \\+ 24;" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-times "\\(unsigned int\\)" 2 "optimized" } } */ +/* { dg-final { scan-tree-dump-not "2147483647" "optimized" } } */ Index: tree.c =================================================================== --- tree.c (revision 248312) +++ tree.c (working copy) @@ -13131,20 +13131,39 @@ drop_tree_overflow (tree t) gcc_checking_assert (TREE_OVERFLOW (t)); /* For tree codes with a sharing machinery re-build the result. */ if (TREE_CODE (t) == INTEGER_CST) return wide_int_to_tree (TREE_TYPE (t), t); /* Otherwise, as all tcc_constants are possibly shared, copy the node and drop the flag. */ t = copy_node (t); TREE_OVERFLOW (t) = 0; + + /* For constants that contain nested constants, drop the flag + from those as well. */ + if (TREE_CODE (t) == COMPLEX_CST) + { + if (TREE_OVERFLOW (TREE_REALPART (t))) + TREE_REALPART (t) = drop_tree_overflow (TREE_REALPART (t)); + if (TREE_OVERFLOW (TREE_IMAGPART (t))) + TREE_IMAGPART (t) = drop_tree_overflow (TREE_IMAGPART (t)); + } + if (TREE_CODE (t) == VECTOR_CST) + { + for (unsigned i = 0; i < VECTOR_CST_NELTS (t); ++i) + { + tree& elt = VECTOR_CST_ELT (t, i); + if (TREE_OVERFLOW (elt)) + elt = drop_tree_overflow (elt); + } + } return t; } /* Given a memory reference expression T, return its base address. The base address of a memory reference expression is the main object being referenced. For instance, the base address for 'array[i].fld[j]' is 'array'. You can think of this as stripping away the offset part from a memory address. This function calls handled_component_p to strip away all the inner