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

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

	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.
This commit is contained in:
Richard Biener 2024-03-12 14:00:05 +01:00
parent 4aa87b8560
commit 73dac51b32
2 changed files with 107 additions and 84 deletions

View file

@ -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

View file

@ -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: