aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Sayle <roger@eyesopen.com>2002-06-15 16:55:24 +0000
committerRoger Sayle <sayle@gcc.gnu.org>2002-06-15 16:55:24 +0000
commit8dcb27ed86eb249675749e35b1440a8ccfd03881 (patch)
treec9fc91c5bbced804e712ce47aaa7397c5a3ed98d
parentf7d3c5f00586f93c1a5a46ebbffa14dce150aae7 (diff)
downloadgcc-8dcb27ed86eb249675749e35b1440a8ccfd03881.zip
gcc-8dcb27ed86eb249675749e35b1440a8ccfd03881.tar.gz
gcc-8dcb27ed86eb249675749e35b1440a8ccfd03881.tar.bz2
fold-const.c (comparison_to_compcode): New function to convert an comparison TREE CODE into a bit-based representation.
* 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. From-SVN: r54647
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/fold-const.c111
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/compare-1.c119
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/compare-2.c24
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/compare-3.c86
6 files changed, 355 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 75ee853..b190a54 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2002-06-15 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.
+
2002-06-15 Aldy Hernandez <aldyh@redhat.com>
* tm.texi (MEMBER_TYPE_FORCES_BLK): Document MODE argument.
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 5c04d78..f9f3a64 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -72,6 +72,8 @@ static int size_htab_eq PARAMS ((const void *, const void *));
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 *));
@@ -115,6 +117,18 @@ static bool fold_real_zero_addition_p PARAMS ((tree, tree, int));
#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
@@ -1709,6 +1723,61 @@ swap_tree_comparison (code)
}
}
+
+/* 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
@@ -3498,6 +3567,48 @@ fold_truthop (code, truth_type, lhs, rhs)
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
with expensive branches. In this case, this isn't a comparison
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ee641bc..68a9cc1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2002-06-15 Roger Sayle <roger@eyesopen.com>
+
+ * 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.
+
2002-06-13 Richard Henderson <rth@redhat.com>
* g++.old-deja/g++.abi/vtable2.C (INC_VDATA): New. Define for
diff --git a/gcc/testsuite/gcc.c-torture/execute/compare-1.c b/gcc/testsuite/gcc.c-torture/execute/compare-1.c
new file mode 100644
index 0000000..78b4650
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/compare-1.c
@@ -0,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;
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/compare-2.c b/gcc/testsuite/gcc.c-torture/execute/compare-2.c
new file mode 100644
index 0000000..858df29
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/compare-2.c
@@ -0,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;
+}
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/compare-3.c b/gcc/testsuite/gcc.c-torture/execute/compare-3.c
new file mode 100644
index 0000000..6549c90
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/compare-3.c
@@ -0,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__ */
+