https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114084
--- Comment #6 from Jakub Jelinek <jakub at gcc dot gnu.org> --- As in the following patch, which is supposed to track the origin of the 6 something0 variables in bitmasks, bit 1 means it comes (partly) from op0, bit 2 means it comes (partly) from op1. --- gcc/fold-const.cc.jj 2024-02-24 09:49:09.098815803 +0100 +++ gcc/fold-const.cc 2024-02-24 11:01:34.266513041 +0100 @@ -11779,6 +11779,15 @@ fold_binary_loc (location_t loc, enum tr + (lit0 != 0) + (lit1 != 0) + (minus_lit0 != 0) + (minus_lit1 != 0)) > 2) { + int var0_origin = (var0 != 0) + 2 * (var1 != 0); + int minus_var0_origin + = (minus_var0 != 0) + 2 * (minus_var1 != 0); + int con0_origin = (con0 != 0) + 2 * (con1 != 0); + int minus_con0_origin + = (minus_con0 != 0) + 2 * (minus_con1 != 0); + int lit0_origin = (lit0 != 0) + 2 * (lit1 != 0); + int minus_lit0_origin + = (minus_lit0 != 0) + 2 * (minus_lit1 != 0); var0 = associate_trees (loc, var0, var1, code, atype); minus_var0 = associate_trees (loc, minus_var0, minus_var1, code, atype); @@ -11791,15 +11800,19 @@ fold_binary_loc (location_t loc, enum tr if (minus_var0 && var0) { + var0_origin |= minus_var0_origin; var0 = associate_trees (loc, var0, minus_var0, MINUS_EXPR, atype); minus_var0 = 0; + minus_var0_origin = 0; } if (minus_con0 && con0) { + con0_origin |= minus_con0_origin; con0 = associate_trees (loc, con0, minus_con0, MINUS_EXPR, atype); minus_con0 = 0; + minus_con0_origin = 0; } /* Preserve the MINUS_EXPR if the negative part of the literal is @@ -11815,15 +11828,19 @@ fold_binary_loc (location_t loc, enum tr /* But avoid ending up with only negated parts. */ && (var0 || con0)) { + minus_lit0_origin |= lit0_origin; minus_lit0 = associate_trees (loc, minus_lit0, lit0, MINUS_EXPR, atype); lit0 = 0; + lit0_origin = 0; } else { + lit0_origin |= minus_lit0_origin; lit0 = associate_trees (loc, lit0, minus_lit0, MINUS_EXPR, atype); minus_lit0 = 0; + minus_lit0_origin = 0; } } @@ -11833,37 +11850,51 @@ fold_binary_loc (location_t loc, enum tr return NULL_TREE; /* Eliminate lit0 and minus_lit0 to con0 and minus_con0. */ + con0_origin |= lit0_origin; con0 = associate_trees (loc, con0, lit0, code, atype); - lit0 = 0; + minus_con0_origin |= minus_lit0_origin; minus_con0 = associate_trees (loc, minus_con0, minus_lit0, code, atype); - minus_lit0 = 0; /* Eliminate minus_con0. */ if (minus_con0) { if (con0) - con0 = associate_trees (loc, con0, minus_con0, - MINUS_EXPR, atype); + { + con0_origin |= minus_con0_origin; + con0 = associate_trees (loc, con0, minus_con0, + MINUS_EXPR, atype); + } else if (var0) - var0 = associate_trees (loc, var0, minus_con0, - MINUS_EXPR, atype); + { + var0_origin |= minus_con0_origin; + var0 = associate_trees (loc, var0, minus_con0, + MINUS_EXPR, atype); + } else gcc_unreachable (); - minus_con0 = 0; } /* Eliminate minus_var0. */ if (minus_var0) { if (con0) - con0 = associate_trees (loc, con0, minus_var0, - MINUS_EXPR, atype); + { + con0_origin |= minus_var0_origin; + con0 = associate_trees (loc, con0, minus_var0, + MINUS_EXPR, atype); + } else gcc_unreachable (); - minus_var0 = 0; } + /* Reassociate only if there has been any actual association + between subtrees from op0 and subtrees from op1 in at + least one of the operands, otherwise we risk infinite + recursion. See PR114084. */ + if (var0_origin != 3 && con0_origin != 3) + return NULL_TREE; + return fold_convert_loc (loc, type, associate_trees (loc, var0, con0, code, atype));