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] Simplify (x<y) || (x==y) into x <= y (take 2)


After giving much thought to Joseph Myers' comments on the previous
version of this patch, I completely agree that the middle-end
should avoid producing warning messages unless the user's code is
actually at fault.  As improvements are made to GCC's constant
folding transformations, it seems inappropriate to "warn" the user
of properties of the code that may not be obvious from looking at
the original source.  Especially as it was impossible to disable
the "informational" warnings generated by my previous patch.

The revision below now silently optimizes away suitable comparisons.

This patch has been tested on i686-pc-linux-gnu with both "make
bootstrap" and "make -k check", all languages except Ada and treelang,
with no new regressions.  I've removed the previous gcc.dg test that
checked that warnings were being issued, and have replaced it with a
"link_error" test that checks the optimization is being applied in
the cases that would previously warn.


Ok for mainline?


2002-06-07  Roger Sayle  <roger@eyesopen.com>

	* fold-const.c (comparison_to_compcode): New function to convert
	an comparison TREE CODE into a bit-based representation.
	(compcode_to_comparison): New function to convert from this bit
	based representation back to a comparison TREE CODE.
	(fold_truthop): Simplify (x<y) && (x==y) and related composite
	comparisons.

	* gcc.c-tortuture/execute/compare-1.c: New test case.
	* gcc.c-tortuture/execute/compare-2.c: New test case.
	* gcc.c-tortuture/execute/compare-3.c: New test case.


Index: fold-const.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/fold-const.c,v
retrieving revision 1.208
diff -c -3 -p -r1.208 fold-const.c
*** fold-const.c	4 Jun 2002 07:07:37 -0000	1.208
--- fold-const.c	7 Jun 2002 16:22:03 -0000
*************** static int size_htab_eq		PARAMS ((const
*** 72,77 ****
--- 72,79 ----
  static tree fold_convert	PARAMS ((tree, tree));
  static enum tree_code invert_tree_comparison PARAMS ((enum tree_code));
  static enum tree_code swap_tree_comparison PARAMS ((enum tree_code));
+ static int comparison_to_compcode PARAMS ((enum tree_code));
+ static enum tree_code compcode_to_comparison PARAMS ((int));
  static int truth_value_p	PARAMS ((enum tree_code));
  static int operand_equal_for_comparison_p PARAMS ((tree, tree, tree));
  static int twoval_comparison_p	PARAMS ((tree, tree *, tree *, int *));
*************** static bool fold_real_zero_addition_p	PA
*** 115,120 ****
--- 117,134 ----
  #define CHARMASK 0x7f
  #endif

+ /* The following constants represent a bit based encoding of GCC's
+    comparison operators.  This encoding simplifies transformations
+    on relational comparison operators, such as AND and OR.  */
+ #define COMPCODE_FALSE   0
+ #define COMPCODE_LT      1
+ #define COMPCODE_EQ      2
+ #define COMPCODE_LE      3
+ #define COMPCODE_GT      4
+ #define COMPCODE_NE      5
+ #define COMPCODE_GE      6
+ #define COMPCODE_TRUE    7
+
  /* We know that A1 + B1 = SUM1, using 2's complement arithmetic and ignoring
     overflow.  Suppose A, B and SUM have the same respective signs as A1, B1,
     and SUM1.  Then this yields nonzero if overflow occurred during the
*************** swap_tree_comparison (code)
*** 1707,1712 ****
--- 1721,1781 ----
      }
  }

+
+ /* Convert a comparison tree code from an enum tree_code representation
+    into a compcode bit-based encoding.  This function is the inverse of
+    compcode_to_comparison.  */
+
+ static int
+ comparison_to_compcode (code)
+      enum tree_code code;
+ {
+   switch (code)
+     {
+     case LT_EXPR:
+       return COMPCODE_LT;
+     case EQ_EXPR:
+       return COMPCODE_EQ;
+     case LE_EXPR:
+       return COMPCODE_LE;
+     case GT_EXPR:
+       return COMPCODE_GT;
+     case NE_EXPR:
+       return COMPCODE_NE;
+     case GE_EXPR:
+       return COMPCODE_GE;
+     default:
+       abort ();
+     }
+ }
+
+ /* Convert a compcode bit-based encoding of a comparison operator back
+    to GCC's enum tree_code representation.  This function is the
+    inverse of comparison_to_compcode.  */
+
+ static enum tree_code
+ compcode_to_comparison (code)
+      int code;
+ {
+   switch (code)
+     {
+     case COMPCODE_LT:
+       return LT_EXPR;
+     case COMPCODE_EQ:
+       return EQ_EXPR;
+     case COMPCODE_LE:
+       return LE_EXPR;
+     case COMPCODE_GT:
+       return GT_EXPR;
+     case COMPCODE_NE:
+       return NE_EXPR;
+     case COMPCODE_GE:
+       return GE_EXPR;
+     default:
+       abort ();
+     }
+ }
+
  /* Return nonzero if CODE is a tree code that represents a truth value.  */

  static int
*************** fold_truthop (code, truth_type, lhs, rhs
*** 3495,3500 ****
--- 3564,3611 ----
    lr_arg = TREE_OPERAND (lhs, 1);
    rl_arg = TREE_OPERAND (rhs, 0);
    rr_arg = TREE_OPERAND (rhs, 1);
+
+   /* Simplify (x<y) && (x==y) into (x<=y) and related optimizations.  */
+   if (simple_operand_p (ll_arg)
+       && simple_operand_p (lr_arg)
+       && !FLOAT_TYPE_P (TREE_TYPE (ll_arg)))
+     {
+       int compcode;
+
+       if (operand_equal_p (ll_arg, rl_arg, 0)
+           && operand_equal_p (lr_arg, rr_arg, 0))
+         {
+           int lcompcode, rcompcode;
+
+           lcompcode = comparison_to_compcode (lcode);
+           rcompcode = comparison_to_compcode (rcode);
+           compcode = (code == TRUTH_AND_EXPR)
+                      ? lcompcode & rcompcode
+                      : lcompcode | rcompcode;
+         }
+       else if (operand_equal_p (ll_arg, rr_arg, 0)
+                && operand_equal_p (lr_arg, rl_arg, 0))
+         {
+           int lcompcode, rcompcode;
+
+           rcode = swap_tree_comparison (rcode);
+           lcompcode = comparison_to_compcode (lcode);
+           rcompcode = comparison_to_compcode (rcode);
+           compcode = (code == TRUTH_AND_EXPR)
+                      ? lcompcode & rcompcode
+                      : lcompcode | rcompcode;
+         }
+       else
+ 	compcode = -1;
+
+       if (compcode == COMPCODE_TRUE)
+ 	return convert (truth_type, integer_one_node);
+       else if (compcode == COMPCODE_FALSE)
+ 	return convert (truth_type, integer_zero_node);
+       else if (compcode != -1)
+ 	return build (compcode_to_comparison (compcode),
+ 		      truth_type, ll_arg, lr_arg);
+     }

    /* If the RHS can be evaluated unconditionally and its operands are
       simple, it wins to evaluate the RHS unconditionally on machines
*** /dev/null	Thu Aug 30 14:30:55 2001
--- gcc.c-torture/execute/compare-1.c	Fri Jun  7 16:30:56 2002
***************
*** 0 ****
--- 1,119 ----
+ /* Copyright (C) 2002 Free Software Foundation.
+
+    Test for correctness of composite comparisons.
+
+    Written by Roger Sayle, 3rd June 2002.  */
+
+ extern void abort (void);
+
+ int ieq (int x, int y, int ok)
+ {
+   if ((x<=y) && (x>=y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+
+   if ((x<=y) && (x==y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+
+   if ((x<=y) && (y<=x))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+
+   if ((y==x) && (x<=y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int ine (int x, int y, int ok)
+ {
+   if ((x<y) || (x>y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int ilt (int x, int y, int ok)
+ {
+   if ((x<y) && (x!=y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int ile (int x, int y, int ok)
+ {
+   if ((x<y) || (x==y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int igt (int x, int y, int ok)
+ {
+   if ((x>y) && (x!=y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int ige (int x, int y, int ok)
+ {
+   if ((x>y) || (x==y))
+     {
+       if (!ok) abort ();
+     }
+   else
+     if (ok) abort ();
+ }
+
+ int
+ main ()
+ {
+   ieq (1, 4, 0);
+   ieq (3, 3, 1);
+   ieq (5, 2, 0);
+
+   ine (1, 4, 1);
+   ine (3, 3, 0);
+   ine (5, 2, 1);
+
+   ilt (1, 4, 1);
+   ilt (3, 3, 0);
+   ilt (5, 2, 0);
+
+   ile (1, 4, 1);
+   ile (3, 3, 1);
+   ile (5, 2, 0);
+
+   igt (1, 4, 0);
+   igt (3, 3, 0);
+   igt (5, 2, 1);
+
+   ige (1, 4, 0);
+   ige (3, 3, 1);
+   ige (5, 2, 1);
+
+   return 0;
+ }
+
*** /dev/null	Thu Aug 30 14:30:55 2001
--- gcc.c-torture/execute/compare-2.c	Fri Jun  7 16:30:56 2002
***************
*** 0 ****
--- 1,24 ----
+ /* Copyright (C) 2002 Free Software Foundation.
+
+    Ensure that the composite comparison optimization doesn't misfire
+    and attempt to combine a signed comparison with an unsigned one.
+
+    Written by Roger Sayle, 3rd June 2002.  */
+
+ extern void abort (void);
+
+ int
+ foo (int x, int y)
+ {
+   /* If miscompiled the following may become "x == y".  */
+   return (x<=y) && ((unsigned int)x >= (unsigned int)y);
+ }
+
+ int
+ main ()
+ {
+   if (! foo (-1,0))
+     abort ();
+   return 0;
+ }
+
*** /dev/null	Thu Aug 30 14:30:55 2001
--- gcc.c-torture/execute/compare-3.c	Fri Jun  7 16:30:56 2002
***************
*** 0 ****
--- 1,86 ----
+ /* Copyright (C) 2002 Free Software Foundation.
+
+    Test for composite comparison always true/false optimization.
+
+    Written by Roger Sayle, 7th June 2002.  */
+
+ extern void link_error0 ();
+ extern void link_error1 ();
+
+ void
+ test1 (int x, int y)
+ {
+   if ((x==y) && (x!=y))
+     link_error0();
+ }
+
+ void
+ test2 (int x, int y)
+ {
+   if ((x<y) && (x>y))
+     link_error0();
+ }
+
+ void
+ test3 (int x, int y)
+ {
+   if ((x<y) && (y<x))
+     link_error0();
+ }
+
+ void
+ test4 (int x, int y)
+ {
+   if ((x==y) || (x!=y))
+     {
+     }
+   else
+     link_error1 ();
+ }
+
+ void
+ test5 (int x, int y)
+ {
+   if ((x>=y) || (x<y))
+     {
+     }
+   else
+     link_error1 ();
+ }
+
+ void
+ test6 (int x, int y)
+ {
+   if ((x<=y) || (y<x))
+     {
+     }
+   else
+     link_error1 ();
+ }
+
+ void
+ all_tests (int x, int y)
+ {
+   test1 (x, y);
+   test2 (x, y);
+   test3 (x, y);
+   test4 (x, y);
+   test5 (x, y);
+   test6 (x, y);
+ }
+
+ int
+ main ()
+ {
+   all_tests (0, 0);
+   all_tests (1, 2);
+   all_tests (4, 3);
+
+   return 0;
+ }
+
+ #ifndef __OPTIMIZE__
+ void link_error0() {}
+ void link_error1() {}
+ #endif /* ! __OPTIMIZE__ */
+

Roger
--
Roger Sayle,                         E-mail: roger@eyesopen.com
OpenEye Scientific Software,         WWW: http://www.eyesopen.com/
Suite 1107, 3600 Cerrillos Road,     Tel: (+1) 505-473-7385
Santa Fe, New Mexico, 87507.         Fax: (+1) 505-473-0833


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