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));

Reply via email to