This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[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;
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]