The following addresses endless recursion in the
chrec_fold_{plus,multiply} functions when handling sign-conversions.
We only need to apply tricks when we'd fail (there's a chrec in the
converted operand) and we need to make sure to not turn the other
operand into something worse (for the chrec-vs-chrec case).

Bootstrapped and tested on x86_64-unknown-linux-gnu, pushed.

        PR tree-optimization/114121
        * tree-chrec.cc (chrec_fold_plus_1): Guard recursion with
        converted operand properly.
        (chrec_fold_multiply): Likewise.  Handle missed recursion.

        * gcc.dg/torture/pr114312.c: New testcase.
---
 gcc/testsuite/gcc.dg/torture/pr114312.c |  15 ++
 gcc/tree-chrec.cc                       | 176 +++++++++++++-----------
 2 files changed, 107 insertions(+), 84 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr114312.c

diff --git a/gcc/testsuite/gcc.dg/torture/pr114312.c 
b/gcc/testsuite/gcc.dg/torture/pr114312.c
new file mode 100644
index 00000000000..c508c64ed19
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr114312.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target bitint } */
+
+#if __BITINT_MAXWIDTH__ >= 129
+typedef _BitInt(129) B;
+B b;
+
+B
+foo(void)
+{
+  _BitInt(64) a = 1;
+  a &= b * b;
+  return b << a;
+}
+#endif
diff --git a/gcc/tree-chrec.cc b/gcc/tree-chrec.cc
index 7cd0ebc1010..1b2ed753551 100644
--- a/gcc/tree-chrec.cc
+++ b/gcc/tree-chrec.cc
@@ -251,23 +251,27 @@ chrec_fold_plus_1 (enum tree_code code, tree type,
          return chrec_fold_plus_poly_poly (code, type, op0, op1);
 
        CASE_CONVERT:
-         {
-           /* We can strip sign-conversions to signed by performing the
-              operation in unsigned.  */
-           tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
-           if (INTEGRAL_TYPE_P (type)
-               && INTEGRAL_TYPE_P (optype)
-               && tree_nop_conversion_p (type, optype)
-               && TYPE_UNSIGNED (optype))
-             return chrec_convert (type,
-                                   chrec_fold_plus_1 (code, optype,
-                                                      chrec_convert (optype,
-                                                                     op0, 
NULL),
-                                                      TREE_OPERAND (op1, 0)),
-                                   NULL);
-           if (tree_contains_chrecs (op1, NULL))
+         if (tree_contains_chrecs (op1, NULL))
+           {
+             /* We can strip sign-conversions to signed by performing the
+                operation in unsigned.  */
+             tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
+             if (INTEGRAL_TYPE_P (type)
+                 && INTEGRAL_TYPE_P (optype)
+                 && tree_nop_conversion_p (type, optype)
+                 && TYPE_UNSIGNED (optype))
+               {
+                 tree tem = chrec_convert (optype, op0, NULL);
+                 if (TREE_CODE (tem) == POLYNOMIAL_CHREC)
+                   return chrec_convert (type,
+                                         chrec_fold_plus_1 (code, optype,
+                                                            tem,
+                                                            TREE_OPERAND
+                                                              (op1, 0)),
+                                         NULL);
+               }
              return chrec_dont_know;
-         }
+           }
          /* FALLTHRU */
 
        default:
@@ -284,26 +288,27 @@ chrec_fold_plus_1 (enum tree_code code, tree type,
        }
 
     CASE_CONVERT:
-      {
-       /* We can strip sign-conversions to signed by performing the
-          operation in unsigned.  */
-       tree optype = TREE_TYPE (TREE_OPERAND (op0, 0));
-       if (INTEGRAL_TYPE_P (type)
-           && INTEGRAL_TYPE_P (optype)
-           && tree_nop_conversion_p (type, optype)
-           && TYPE_UNSIGNED (optype))
-         return chrec_convert (type,
-                               chrec_fold_plus_1 (code, optype,
-                                                  TREE_OPERAND (op0, 0),
-                                                  chrec_convert (optype,
-                                                                 op1, NULL)),
-                               NULL);
-       if (tree_contains_chrecs (op0, NULL))
+      if (tree_contains_chrecs (op0, NULL))
+       {
+         /* We can strip sign-conversions to signed by performing the
+            operation in unsigned.  */
+         tree optype = TREE_TYPE (TREE_OPERAND (op0, 0));
+         if (INTEGRAL_TYPE_P (type)
+             && INTEGRAL_TYPE_P (optype)
+             && tree_nop_conversion_p (type, optype)
+             && TYPE_UNSIGNED (optype))
+           return chrec_convert (type,
+                                 chrec_fold_plus_1 (code, optype,
+                                                    TREE_OPERAND (op0, 0),
+                                                    chrec_convert (optype,
+                                                                   op1, NULL)),
+                                 NULL);
          return chrec_dont_know;
-      }
+       }
       /* FALLTHRU */
 
     default:
+      gcc_checking_assert (!tree_contains_chrecs (op0, NULL));
       switch (TREE_CODE (op1))
        {
        case POLYNOMIAL_CHREC:
@@ -325,24 +330,24 @@ chrec_fold_plus_1 (enum tree_code code, tree type,
                                    : build_int_cst_type (type, -1)));
 
        CASE_CONVERT:
-         {
-           /* We can strip sign-conversions to signed by performing the
-              operation in unsigned.  */
-           tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
-           if (INTEGRAL_TYPE_P (type)
-               && INTEGRAL_TYPE_P (optype)
-               && tree_nop_conversion_p (type, optype)
-               && TYPE_UNSIGNED (optype))
-             return chrec_convert (type,
-                                   chrec_fold_plus_1 (code, optype,
-                                                      chrec_convert (optype,
-                                                                     op0, 
NULL),
-                                                      TREE_OPERAND (op1, 0)),
-                                   NULL);
-         }
-
          if (tree_contains_chrecs (op1, NULL))
-           return chrec_dont_know;
+           {
+             /* We can strip sign-conversions to signed by performing the
+                operation in unsigned.  */
+             tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
+             if (INTEGRAL_TYPE_P (type)
+                 && INTEGRAL_TYPE_P (optype)
+                 && tree_nop_conversion_p (type, optype)
+                 && TYPE_UNSIGNED (optype))
+               return chrec_convert (type,
+                                     chrec_fold_plus_1 (code, optype,
+                                                        chrec_convert (optype,
+                                                                       op0,
+                                                                       NULL),
+                                                        TREE_OPERAND (op1, 0)),
+                                     NULL);
+             return chrec_dont_know;
+           }
          /* FALLTHRU */
 
        default:
@@ -440,24 +445,26 @@ chrec_fold_multiply (tree type,
          return chrec_fold_multiply_poly_poly (type, op0, op1);
 
        CASE_CONVERT:
-         {
-           /* We can strip sign-conversions to signed by performing the
-              operation in unsigned.  */
-           tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
-           if (INTEGRAL_TYPE_P (type)
-               && INTEGRAL_TYPE_P (optype)
-               && tree_nop_conversion_p (type, optype)
-               && TYPE_UNSIGNED (optype))
-             return chrec_convert (type,
-                                   chrec_fold_multiply (optype,
-                                                        chrec_convert (optype,
-                                                                       op0, 
NULL),
-                                                        TREE_OPERAND (op1, 0)),
-                                   NULL);
-         }
-
          if (tree_contains_chrecs (op1, NULL))
-           return chrec_dont_know;
+           {
+             /* We can strip sign-conversions to signed by performing the
+                operation in unsigned.  */
+             tree optype = TREE_TYPE (TREE_OPERAND (op1, 0));
+             if (INTEGRAL_TYPE_P (type)
+                 && INTEGRAL_TYPE_P (optype)
+                 && tree_nop_conversion_p (type, optype)
+                 && TYPE_UNSIGNED (optype))
+               {
+                 tree tem = chrec_convert (optype, op0, NULL);
+                 if (TREE_CODE (tem) == POLYNOMIAL_CHREC)
+                   return chrec_convert (type,
+                                         chrec_fold_multiply (optype, tem,
+                                                              TREE_OPERAND
+                                                                (op1, 0)),
+                                         NULL);
+               }
+             return chrec_dont_know;
+           }
          /* FALLTHRU */
 
        default:
@@ -506,27 +513,28 @@ chrec_fold_multiply (tree type,
        }
 
     CASE_CONVERT:
-      {
-       /* We can strip sign-conversions to signed by performing the
-          operation in unsigned.  */
-       tree optype = TREE_TYPE (TREE_OPERAND (op0, 0));
-       if (INTEGRAL_TYPE_P (type)
-           && INTEGRAL_TYPE_P (optype)
-           && tree_nop_conversion_p (type, optype)
-           && TYPE_UNSIGNED (optype))
-         return chrec_convert (type,
-                               chrec_fold_multiply (optype,
-                                                    TREE_OPERAND (op0, 0),
-                                                    chrec_convert (optype,
-                                                                   op1, NULL)),
-                               NULL);
-      }
-
       if (tree_contains_chrecs (op0, NULL))
-       return chrec_dont_know;
+       {
+         /* We can strip sign-conversions to signed by performing the
+            operation in unsigned.  */
+         tree optype = TREE_TYPE (TREE_OPERAND (op0, 0));
+         if (INTEGRAL_TYPE_P (type)
+             && INTEGRAL_TYPE_P (optype)
+             && tree_nop_conversion_p (type, optype)
+             && TYPE_UNSIGNED (optype))
+           return chrec_convert (type,
+                                 chrec_fold_multiply (optype,
+                                                      TREE_OPERAND (op0, 0),
+                                                      chrec_convert (optype,
+                                                                     op1,
+                                                                     NULL)),
+                                 NULL);
+         return chrec_dont_know;
+       }
       /* FALLTHRU */
 
     default:
+      gcc_checking_assert (!tree_contains_chrecs (op0, NULL));
       if (integer_onep (op0))
        return op1;
 
@@ -540,7 +548,7 @@ chrec_fold_multiply (tree type,
 
        CASE_CONVERT:
          if (tree_contains_chrecs (op1, NULL))
-           return chrec_dont_know;
+           return chrec_fold_multiply (type, op1, op0);
          /* FALLTHRU */
 
        default:
-- 
2.35.3

Reply via email to