diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc index 80e211e18c0edb2b4524a002f3c794f6c285e44b..43105d20be35c8f9853b0f0ef647b899ffb66260 100644 --- a/gcc/fold-const.cc +++ b/gcc/fold-const.cc @@ -11779,6 +11779,15 @@ fold_binary_loc (location_t loc, enum tree_code code, tree type, + (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 tree_code code, tree type, 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 tree_code code, tree type, /* 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 tree_code code, tree type, 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)); diff --git a/gcc/testsuite/gcc.dg/bitint-94.c b/gcc/testsuite/gcc.dg/bitint-94.c new file mode 100644 index 0000000000000000000000000000000000000000..ca32043a095d2e6eae2d2cb0d1c4ff7d53b08c73 --- /dev/null +++ b/gcc/testsuite/gcc.dg/bitint-94.c @@ -0,0 +1,12 @@ +/* PR middle-end/114084 */ +/* { dg-do compile { target bitint } } */ +/* { dg-options "-std=c23 -pedantic-errors" } */ + +typedef unsigned _BitInt(31) T; +T a, b; + +void +foo (void) +{ + b = (T) ((a | (-1U >> 1)) >> 1 | (a | 5) << 4); +}