This is the regression in the folding of conditional expressions like
unsigned long f1 (int x)
{
return x > 0 ? (unsigned long) x : 0;
}
unsigned long f2 (int x, int y)
{
return x > y ? (unsigned long) x : (unsigned long) y;
}
introduced by the fix for PR middle-end/81814. These conditional expressions
are very common in Ada in the size expressions of unconstrained array types.
The attached patch reinstates a limited version of the optimization that was
disabled by the aforementioned fix. The long term plan is to move the whole
thing to match.pd but I'll leave that to specialists.
Bootstrapped/regtested on x86_64-suse-linux, approved by Richard B. in the
audit trail of the PR, applied on the mainline.
2017-10-25 Eric Botcazou <ebotca...@adacore.com>
PR middle-end/82062
* fold-const.c (operand_equal_for_comparison_p): Also return true
if ARG0 is a simple variant of ARG1 with narrower precision.
(fold_ternary_loc): Always pass unstripped operands to the predicate.
2017-10-25 Eric Botcazou <ebotca...@adacore.com>
* gcc.dg/fold-cond_expr-1.c: Rename to...
* gcc.dg/fold-cond-2.c: ...this.
* gcc.dg/fold-cond-3.c: New test.
--
Eric Botcazou
Index: fold-const.c
===================================================================
--- fold-const.c (revision 254037)
+++ fold-const.c (working copy)
@@ -3366,7 +3366,8 @@ operand_equal_p (const_tree arg0, const_
#undef OP_SAME_WITH_NULL
}
-/* Similar to operand_equal_p, but strip nops first. */
+/* Similar to operand_equal_p, but see if ARG0 might be a variant of ARG1
+ with a different signedness or a narrower precision. */
static bool
operand_equal_for_comparison_p (tree arg0, tree arg1)
@@ -3381,9 +3382,20 @@ operand_equal_for_comparison_p (tree arg
/* Discard any conversions that don't change the modes of ARG0 and ARG1
and see if the inner values are the same. This removes any
signedness comparison, which doesn't matter here. */
- STRIP_NOPS (arg0);
- STRIP_NOPS (arg1);
- if (operand_equal_p (arg0, arg1, 0))
+ tree op0 = arg0;
+ tree op1 = arg1;
+ STRIP_NOPS (op0);
+ STRIP_NOPS (op1);
+ if (operand_equal_p (op0, op1, 0))
+ return true;
+
+ /* Discard a single widening conversion from ARG1 and see if the inner
+ value is the same as ARG0. */
+ if (CONVERT_EXPR_P (arg1)
+ && INTEGRAL_TYPE_P (TREE_TYPE (TREE_OPERAND (arg1, 0)))
+ && TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (arg1, 0)))
+ < TYPE_PRECISION (TREE_TYPE (arg1))
+ && operand_equal_p (arg0, TREE_OPERAND (arg1, 0), 0))
return true;
return false;
@@ -11169,8 +11181,8 @@ fold_ternary_loc (location_t loc, enum t
Also try swapping the arguments and inverting the conditional. */
if (COMPARISON_CLASS_P (arg0)
- && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), arg1)
- && !HONOR_SIGNED_ZEROS (element_mode (arg1)))
+ && operand_equal_for_comparison_p (TREE_OPERAND (arg0, 0), op1)
+ && !HONOR_SIGNED_ZEROS (element_mode (op1)))
{
tem = fold_cond_expr_with_comparison (loc, type, arg0, op1, op2);
if (tem)
/* { dg-do compile } */
/* { dg-options "-fdump-tree-original" } */
unsigned long f1 (int x)
{
return x > 0 ? (unsigned long) x : 0;
}
unsigned long f2 (int x, int y)
{
return x > y ? (unsigned long) x : (unsigned long) y;
}
unsigned long f3 (int x)
{
return x < 0 ? (unsigned long) x : 0;
}
unsigned long f4 (int x, int y)
{
return x < y ? (unsigned long) x : (unsigned long) y;
}
unsigned long f5 (unsigned int x, unsigned int y)
{
return x > y ? (unsigned long) x : (unsigned long) y;
}
unsigned long f6 (unsigned int x, unsigned int y)
{
return x < y ? (unsigned long) x : (unsigned long) y;
}
/* { dg-final { scan-tree-dump-times "MAX_EXPR" 3 "original"} } */
/* { dg-final { scan-tree-dump-times "MIN_EXPR" 3 "original"} } */