https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81097
--- Comment #4 from rguenther at suse dot de <rguenther at suse dot de> --- On Tue, 20 Jun 2017, mpolacek at gcc dot gnu.org wrote: > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81097 > > --- Comment #3 from Marek Polacek <mpolacek at gcc dot gnu.org> --- > Well, my fix was > > --- a/gcc/fold-const.c > +++ b/gcc/fold-const.c > @@ -850,7 +850,8 @@ split_tree (location_t loc, tree in, tree type, enum > tree_code code, > else if (TREE_CONSTANT (in)) > *conp = in; > else if (TREE_CODE (in) == BIT_NOT_EXPR > - && code == PLUS_EXPR) > + && code == PLUS_EXPR > + && negate_expr_p (TREE_OPERAND (in, 0))) > { > /* -X - 1 is folded to ~X, undo that here. Do _not_ do this > when IN is constant. */ > > but it has some fallout it seems. > > Also, the comment says > -X - 1 is folded to ~X, undo that here. > but there was not -X - 1, the bit not came from > ~x | ~y -> ~(x & y) > in match.pd. Yeah, it's not "undoing" but trying to cleverly combine ~x + 1 to x. Possibly the fallout testcases you've seen or some archeology will tell. I think it's really trying to "undo" this transform AFAIR (I remember adding this code). Using negate_expr_p is checking for "easily negatable", you could use a TYPE_OVERFLOW_UNDEFINED check but that would have similar fallout. Or just force the negation to use an unsigned type (my patch does this for the testcase), but I'm not even sure that will work because if the original expr is int then ~x + ~x becomes (int)(-(unsigned)x - (unsigned)x) - 2 and supposedly we can craft x to be so that (int)(-(unsigned)x - (unsigned)x) - 2 will overflow. The associate case is somewhat defensive when associating TYPE_OVERFLOW_UNDEFINED stuff but I'm not sure what it does is enough. I'm currentlyu testing Index: gcc/fold-const.c =================================================================== --- gcc/fold-const.c (revision 249397) +++ gcc/fold-const.c (working copy) @@ -853,9 +853,9 @@ split_tree (location_t loc, tree in, tre && code == PLUS_EXPR) { /* -X - 1 is folded to ~X, undo that here. Do _not_ do this - when IN is constant. */ - *minus_litp = build_one_cst (TREE_TYPE (in)); - var = negate_expr (TREE_OPERAND (in, 0)); + when IN is constant. Convert to TYPE before negating. */ + *minus_litp = build_one_cst (type); + var = negate_expr (fold_convert_loc (loc, type, TREE_OPERAND (in, 0))); } else var = in; which is, as I said, not enough but another testcase is appreciated ;)