diff mbox series

tree-optimization/114121 - chrec_fold_{plus,multiply} and recursion

Message ID 20240312140927.549333858030@sourceware.org
State New
Headers show
Series tree-optimization/114121 - chrec_fold_{plus,multiply} and recursion | expand

Commit Message

Richard Biener March 12, 2024, 2:09 p.m. UTC
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 mbox series

Patch

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: