On Mon, 26 Feb 2024, Jakub Jelinek wrote: > Hi! > > In the following testcase we infinitely recurse during BIT_IOR_EXPR > reassociation. > One operand is (unsigned _BitInt(31)) a << 4 and another operand > 2147483647 >> 1 | 80 where both the right shift and the | 80 > trees have TREE_CONSTANT set, but weren't folded because of delayed > folding, where some foldings are apparently done even in that case > unfortunately. > Now, the fold_binary_loc reassocation code splits both operands into > variable part, minus variable part, constant part, minus constant part, > literal part and minus literal parts, to prevent infinite recursion > punts if there are just 2 parts altogether from the 2 operands and then goes > on with reassociation, merges first the corresponding parts from both > operands and then some further merges. > The problem with the above expressions is that we get 3 different objects, > var0 (the left shift), con1 (the right shift) and lit1 (80), so the infinite > recursion prevention doesn't trigger, and we eventually merge con1 with > lit1, which effectively reconstructs the original op1 and then associate > that with var0 which is original op0, and associate_trees for that case > calls fold_binary. There are some casts involved there too (the T typedef > type and the underlying _BitInt type which are stripped with STRIP_NOPS). > > The following patch attempts to prevent this infinite recursion by tracking > the origin (if certain var comes from nothing - 0, op0 - 1, op1 - 2 or both - > 3) > and propagates it through all the associate_tree calls which merge the vars. > If near the end we'd try to merge what comes solely from op0 with what comes > solely from op1 (or vice versa), the patch punts, because then it isn't any > kind of reassociation between the two operands, if anything it should be > handled when folding the suboperands.
That sounds like a nice thing to do. > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk? OK. Thanks, Richard. > 2024-02-26 Jakub Jelinek <ja...@redhat.com> > > PR middle-end/114084 > * fold-const.cc (fold_binary_loc): Avoid the final associate_trees > if all subtrees of var0 come from one of the op0 or op1 operands > and all subtrees of con0 come from the other one. Don't clear > variables which are never used afterwards. > > * gcc.dg/bitint-94.c: New test. > > --- gcc/fold-const.cc.jj 2024-02-24 09:49:09.098815803 +0100 > +++ gcc/fold-const.cc 2024-02-24 11:08:56.036223491 +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)); > --- gcc/testsuite/gcc.dg/bitint-94.c.jj 2024-02-24 11:18:32.607018363 > +0100 > +++ gcc/testsuite/gcc.dg/bitint-94.c 2024-02-24 11:19:09.023500121 +0100 > @@ -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); > +} > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)