This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Fix PR27302, work towards fixing PR26899, PR26900
- From: Richard Guenther <rguenther at suse dot de>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 9 May 2006 16:57:21 +0200 (CEST)
- Subject: [PATCH] Fix PR27302, work towards fixing PR26899, PR26900
This patch teaches operand_equal_p a set of comparison equalities.
For one, it handles swapping the comparison code, for another, it
handles transforming LE_EXPR to LT_EXPR and GE_EXPR to GT_EXPR and
vice versa, for undefined overflow semantic operations like
int1 + 2 < int2.
This is to work towards the goal of not needing the previously posted
patch for PR26900, but instead improve operand_equal_p and friends
(that PR is a number of iterations analysis problem where exit condition
and loop header condition differ by code and placement of constant
such as i + 1 <= i0 vs. i0 > i)
Bootstrapped and tested on x86_64-unknown-linux-gnu for all languages
including Ada.
Thanks,
Richard.
:ADDPATCH middle-end:
2006-05-09 Richard Guenther <rguenther@suse.de>
PR tree-optimization/27302
PR tree-optimization/26899
PR tree-optimization/26900
* fold-const.c (maybe_add_remove_equality_compare_1): New
function.
(maybe_add_remove_equality_compare): Likewise.
(operand_equal_p): Handle swapped comparisons and comparisons
that can be adjusted to the same code by transforming
LE_EXPR to LT_EXPR or GE_EXPR to GT_EXPR or vice versa.
Index: fold-const.c
===================================================================
*** fold-const.c (revision 113628)
--- fold-const.c (working copy)
*************** truth_value_p (enum tree_code code)
*** 2447,2452 ****
--- 2447,2550 ----
|| code == TRUTH_XOR_EXPR || code == TRUTH_NOT_EXPR);
}
+ /* Helper for maybe_add_remove_equality_compare that tries to do the
+ transformation on ARG0. */
+
+ static tree
+ maybe_add_remove_equality_compare_1 (enum tree_code code, tree type, tree arg0,
+ tree arg1, bool swap)
+ {
+ enum tree_code code0;
+ tree cst0, t;
+ int sgn0;
+
+ /* Match A +- CST code arg1. */
+ code0 = TREE_CODE (arg0);
+ cst0 = NULL_TREE;
+ if (!((code0 == MINUS_EXPR
+ || code0 == PLUS_EXPR)
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST))
+ return NULL_TREE;
+
+ cst0 = TREE_OPERAND (arg0, 1);
+ sgn0 = tree_int_cst_sgn (cst0);
+
+ /* In the transformations below we need cst0 reduced by one in magnitude
+ applied to the expression in arg0. */
+ t = fold_build2 (code0, TREE_TYPE (arg0),
+ TREE_OPERAND (arg0, 0),
+ int_const_binop (sgn0 == -1 ? PLUS_EXPR : MINUS_EXPR, cst0,
+ build_int_cst (TREE_TYPE (cst0), 1), 0));
+
+ /* A - CST < B -> A - CST-1 <= B. */
+ if (code == LT_EXPR
+ && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+ {
+ if (swap)
+ return build2 (GE_EXPR, type, arg1, t);
+ else
+ return build2 (LE_EXPR, type, t, arg1);
+ }
+
+ /* A + CST > B -> A + CST-1 >= B. */
+ if (code == GT_EXPR
+ && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+ {
+ if (swap)
+ return build2 (LE_EXPR, type, arg1, t);
+ else
+ return build2 (GE_EXPR, type, t, arg1);
+ }
+
+ /* A + CST <= B -> A + CST-1 < B. */
+ if (code == LE_EXPR
+ && code0 == ((sgn0 == -1) ? MINUS_EXPR : PLUS_EXPR))
+ {
+ if (swap)
+ return build2 (GT_EXPR, type, arg1, t);
+ else
+ return build2 (LT_EXPR, type, t, arg1);
+ }
+
+ /* A - CST >= B -> A - CST-1 > B. */
+ if (code == GE_EXPR
+ && code0 == ((sgn0 == -1) ? PLUS_EXPR : MINUS_EXPR))
+ {
+ if (swap)
+ return build2 (LT_EXPR, type, arg1, t);
+ else
+ return build2 (GT_EXPR, type, t, arg1);
+ }
+
+ return NULL_TREE;
+ }
+
+ /* Tries to transform the comparison CMP, which is a (LT|LE|GE|GT)_EXPR,
+ into the corresponding comparison without/with the equality part
+ (LE|LT|GT|LE)_EXPR. In addition to this, swap the comparison arguments
+ if SWAP is true. Returns the modified comparison tree or NULL_TREE,
+ if the transformation is not possible. */
+
+ static tree
+ maybe_add_remove_equality_compare (tree cmp, bool swap)
+ {
+ tree t;
+
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (cmp, 0)))
+ || flag_wrapv || flag_trapv)
+ return NULL_TREE;
+
+ t = maybe_add_remove_equality_compare_1 (TREE_CODE (cmp), TREE_TYPE (cmp),
+ TREE_OPERAND (cmp, 0),
+ TREE_OPERAND (cmp, 1), swap);
+ if (t)
+ return t;
+ return maybe_add_remove_equality_compare_1 (swap_tree_comparison (TREE_CODE (cmp)),
+ TREE_TYPE (cmp),
+ TREE_OPERAND (cmp, 1),
+ TREE_OPERAND (cmp, 0), !swap);
+ }
+
/* Return nonzero if two operands (typically of the same tree node)
are necessarily equal. If either argument has side-effects this
function returns zero. FLAGS modifies behavior as follows:
*************** operand_equal_p (tree arg0, tree arg1, u
*** 2489,2494 ****
--- 2587,2645 ----
STRIP_NOPS (arg0);
STRIP_NOPS (arg1);
+ /* In case both args are comparisons but with different comparison
+ code, try to swap the comparison operands of one arg or to adjust
+ constants involved in the comparison if overflow is undefined. */
+ if (TREE_CODE (arg0) != TREE_CODE (arg1)
+ && COMPARISON_CLASS_P (arg0)
+ && COMPARISON_CLASS_P (arg1))
+ {
+ enum tree_code swap_code = swap_tree_comparison (TREE_CODE (arg1));
+ bool swap;
+ tree t;
+
+ /* If we can produce matching tree codes by swapping one comparison,
+ do so. */
+ if (TREE_CODE (arg0) == swap_code)
+ return operand_equal_p (arg0,
+ build2 (swap_code, TREE_TYPE (arg1),
+ TREE_OPERAND (arg1, 1),
+ TREE_OPERAND (arg1, 0)), flags);
+
+ /* If there is possible overflow involved, bail out. */
+ if (TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg0, 1)))
+ || TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (arg1, 1)))
+ || flag_wrapv || flag_trapv)
+ return 0;
+
+ /* In the following we only deal with in addition to swapping the
+ comparison arguments, canonicalizing to the (not-)equality
+ variants of the comparisons. */
+ if (!(((TREE_CODE (arg0) == LE_EXPR
+ || TREE_CODE (arg0) == GE_EXPR)
+ && (TREE_CODE (arg1) == LT_EXPR
+ || TREE_CODE (arg1) == GT_EXPR))
+ || ((TREE_CODE (arg0) == LT_EXPR
+ || TREE_CODE (arg0) == GT_EXPR)
+ && (TREE_CODE (arg1) == LE_EXPR
+ || TREE_CODE (arg1) == GE_EXPR))))
+ return 0;
+
+ /* Try the transformation on both arg0 and arg1. */
+ swap = ((TREE_CODE (arg0) == LT_EXPR && TREE_CODE (arg1) == GE_EXPR)
+ || (TREE_CODE (arg0) == LE_EXPR && TREE_CODE (arg1) == GT_EXPR)
+ || (TREE_CODE (arg0) == GE_EXPR && TREE_CODE (arg1) == LT_EXPR)
+ || (TREE_CODE (arg0) == GT_EXPR && TREE_CODE (arg1) == LE_EXPR));
+ t = maybe_add_remove_equality_compare (arg0, swap);
+ if (t)
+ return operand_equal_p (t, arg1, flags);
+ t = maybe_add_remove_equality_compare (arg1, swap);
+ if (t)
+ return operand_equal_p (arg0, t, flags);
+
+ return 0;
+ }
+
if (TREE_CODE (arg0) != TREE_CODE (arg1)
/* This is needed for conversions and for COMPONENT_REF.
Might as well play it safe and always test this. */
Index: testsuite/gcc.dg/torture/pr27302.c
===================================================================
*** testsuite/gcc.dg/torture/pr27302.c (revision 0)
--- testsuite/gcc.dg/torture/pr27302.c (revision 0)
***************
*** 0 ****
--- 1,51 ----
+ /* { dg-do run } */
+
+ extern void link_error (void);
+
+ void test0 (int a, int b)
+ {
+ if ((a < b) != (b > a))
+ link_error ();
+
+ if ((a - 1 < b) != (a <= b))
+ link_error ();
+ if ((a - 2 < b) != (a - 1 <= b))
+ link_error ();
+ if ((a + -1 < b) != (a <= b))
+ link_error ();
+ if ((a + -2 < b) != (a + -1 <= b))
+ link_error ();
+
+ if ((a + 1 > b) != (a >= b))
+ link_error ();
+ if ((a + 2 > b) != (a + 1 >= b))
+ link_error ();
+ if ((a - -1 > b) != (a >= b))
+ link_error ();
+ if ((a - -2 > b) != (a - -1 >= b))
+ link_error ();
+
+ if ((a + 1 <= b) != (a < b))
+ link_error ();
+ if ((a + 2 <= b) != (a + 1 < b))
+ link_error ();
+ if ((a - -1 <= b) != (a < b))
+ link_error ();
+ if ((a - -2 <= b) != (a - -1 < b))
+ link_error ();
+
+ if ((a - 1 >= b) != (a > b))
+ link_error ();
+ if ((a - 2 >= b) != (a - 1 > b))
+ link_error ();
+ if ((a + -1 >= b) != (a > b))
+ link_error ();
+ if ((a + -2 >= b) != (a + -1 > b))
+ link_error ();
+ }
+
+ int main()
+ {
+ test0 (1, 2);
+ return 0;
+ }