[PATCH v2 2/3] match/fold: Add support for NE, XOR, and EQ to combine_comparisons [PR107881]

Andrea Pinski <[email protected]>
Newsgroups gmane.comp.gcc.patches
Message-ID <[email protected]>
This adds support for !=, ^ and == to combine_comparisons and
uses combine_comparisons in match for those cases instead of what
was previously there. This allows for floating point comparisons to
be merged in some more cases. And simplifies the match code to read.
Also moves up the match pattern that uses combine_comparisons to
above the other comparisons combines so it is matched first.

Changes since v1:
* v2: Add bitwise operators for comparison_code to hide the &0xf. Also
place comparison_code in an anonymous namespace to mark it as local to
the file. Update for the new sytanx of the match pattern.

Bootstrapped and tested on x86_64-linux-gnu.

	PR tree-optimization/107881

gcc/ChangeLog:

	* fold-const.cc (enum comparison_code): Mark underlying type as
	unsigned char. Wrap in an anonymous namespace.
	(operator~): New function.
	(operator|): New function.
	(operator&): New function.
	(operator^): New function.
	(combine_comparisons): Add support for 	NE/XOR and EQ.
	* match.pd (`(a CMP1 b) OP (a CMP2 b)`): Move
	above others and add NE, XOR and EQ to the list of OPs.
	(`(a CMP1 b) ^ (a CMP2 b)`): Remove.
	(`(a CMP1 b) == (a CMP2 b)`): Remove.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/cmpeq-5.c: New test.
	* gcc.dg/tree-ssa/cmpxor-2.c: New test.

Signed-off-by: Andrea Pinski <[email protected]>
---
 gcc/fold-const.cc                        | 54 ++++++++++++++++++-
 gcc/match.pd                             | 66 +++++++-----------------
 gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c  | 51 ++++++++++++++++++
 gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c | 51 ++++++++++++++++++
 4 files changed, 174 insertions(+), 48 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c
 create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c

diff --git a/gcc/fold-const.cc b/gcc/fold-const.cc
index 420e3185a2a..b0f2e51aec1 100644
--- a/gcc/fold-const.cc
+++ b/gcc/fold-const.cc
@@ -100,10 +100,11 @@ int folding_initializer = 0;
    during folding in that context.  */
 bool folding_cxx_constexpr = false;
 
+namespace {
 /* 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.  */
-enum comparison_code {
+enum comparison_code : unsigned char {
   COMPCODE_FALSE = 0,
   COMPCODE_LT = 1,
   COMPCODE_EQ = 2,
@@ -122,6 +123,48 @@ enum comparison_code {
   COMPCODE_TRUE = 15
 };
 
+// Implements bitwise operators on comparison_code so the
+// upper unused bits are cleared.
+
+// Implements bitwise not on comparison_code
+// clearing the upper unused bits.
+comparison_code
+operator ~(comparison_code cmp)
+{
+  unsigned char newcmp = cmp;
+  newcmp = ~newcmp & 0xF;
+  return (comparison_code)newcmp;
+}
+
+// Implements bitwise ior on comparison_code.
+comparison_code
+operator |(comparison_code cmp0, comparison_code cmp1)
+{
+  unsigned char newcmp = ((unsigned char)cmp0) | cmp1;
+  newcmp = newcmp & 0xF;
+  return (comparison_code)newcmp;
+}
+
+// Implements bitwise and on comparison_code.
+comparison_code
+operator &(comparison_code cmp0, comparison_code cmp1)
+{
+  unsigned char newcmp = ((unsigned char)cmp0) & cmp1;
+  newcmp = newcmp & 0xF;
+  return (comparison_code)newcmp;
+}
+
+// Implements bitwise xor on comparison_code.
+comparison_code
+operator ^(comparison_code cmp0, comparison_code cmp1)
+{
+  unsigned char newcmp = ((unsigned char)cmp0) ^ cmp1;
+  newcmp = newcmp & 0xF;
+  return (comparison_code)newcmp;
+}
+
+}
+
 static bool negate_expr_p (tree);
 static tree negate_expr (tree);
 static tree associate_trees (location_t, tree, tree, enum tree_code, tree);
@@ -2964,6 +3007,15 @@ combine_comparisons (enum tree_code code, enum tree_code lcode,
       compcode = lcompcode | rcompcode;
       break;
 
+    case BIT_XOR_EXPR:
+    case NE_EXPR:
+      compcode = lcompcode ^ rcompcode;
+      break;
+
+    case EQ_EXPR:
+      compcode = ~(lcompcode ^ rcompcode);
+      break;
+
     default:
       return ERROR_MARK;
     }
diff --git a/gcc/match.pd b/gcc/match.pd
index d255795c8dd..dfcbf961948 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -3688,6 +3688,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
   (gt @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); }))))
 
+/* Optimize (a CMP b) &| (a CMP b)
+   using the helper combine_comparisons function.  */
+(for bitop (bit_and bit_ior bit_xor ne eq)
+ (for cmp1 (tcc_comparison)
+  (for cmp2 (tcc_comparison)
+   (simplify
+    (bitop (cmp1 @0 @1) (cmp2 @0 @1))
+    (with {
+      tree_code rescmpcode;
+      tree res;
+      bool honor_nans = HONOR_NANS (@0);
+      rescmpcode = combine_comparisons (bitop, cmp1, cmp2,
+					type, honor_nans, &res);
+     }
+     (if (rescmpcode == INTEGER_CST)
+      { res; }
+      (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
+       (rescmpcode @0 @1))))))))
+
 /* Convert (X == CST1) && ((other)X OP2 CST2) to a known value
    based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
 /* Convert (X == Y) && (X OP2 Y) to a known value if X is an integral type.
@@ -3973,53 +3992,6 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       { constant_boolean_node (true, type); })
      ))))))
 
-/* Optimize (a CMP b) ^ (a CMP b)  */
-/* Optimize (a CMP b) != (a CMP b)  */
-(for op (bit_xor ne)
- (for cmp1 (lt lt lt le le le)
-      cmp2 (gt eq ne ge eq ne)
-      rcmp (ne le gt ne lt ge)
-  (simplify
-   (op:c (cmp1:c @0 @1) (cmp2 @0 @1))
-   (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
-      || POINTER_TYPE_P (TREE_TYPE (@0))
-      || ((VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1))
-	   || VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (@1)))
-      && expand_vec_cmp_expr_p (TREE_TYPE (@0), type, rcmp)))
-    (rcmp @0 @1)))))
-
-/* Optimize (a CMP b) == (a CMP b)  */
-(for cmp1 (lt lt lt le le le)
-     cmp2 (gt eq ne ge eq ne)
-     rcmp (eq gt le eq ge lt)
- (simplify
-  (eq:c (cmp1:c @0 @1) (cmp2 @0 @1))
-  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
-		|| POINTER_TYPE_P (TREE_TYPE (@0))
-      || ((VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1))
-	   || VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (@1)))
-      && expand_vec_cmp_expr_p (TREE_TYPE (@0), type,  rcmp)))
-    (rcmp @0 @1))))
-
-/* Optimize (a CMP b) &| (a CMP b)
-   using the helper combine_comparisons function.  */
-(for bitop (bit_and bit_ior)
- (for cmp1 (tcc_comparison)
-  (for cmp2 (tcc_comparison)
-   (simplify
-    (bitop (cmp1 @0 @1) (cmp2 @0 @1))
-    (with {
-      tree_code rescmpcode;
-      tree res;
-      bool honor_nans = HONOR_NANS (@0);
-      rescmpcode = combine_comparisons (bitop, cmp1, cmp2,
-					type, honor_nans, &res);
-     }
-     (if (rescmpcode == INTEGER_CST)
-      { res; }
-      (if (TREE_CODE_CLASS (rescmpcode) == tcc_comparison)
-       (rescmpcode @0 @1))))))))
-
 /* (type)([0,1]@a != 0) -> (type)a
    (type)([0,1]@a == 1) -> (type)a
    (type)([0,1]@a == 0) -> a ^ 1
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c
new file mode 100644
index 00000000000..16dc35ca39e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpeq-5.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */
+/* PR tree-optimization/107881 */
+
+_Bool ltgt_eq(float a, float b)
+{
+  _Bool c = a < b;
+  _Bool d = a > b;
+  return c == d; // a u== b
+}
+/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. u== b_\[0-9\]+.D.|b_\[0-9\]+.D. u== a_\[0-9\]+.D." "optimized" } } */
+
+_Bool lteq_eq(float x, float y)
+{
+  _Bool c = x < y;
+  _Bool d = x == y;
+  return c == d; // x u> y
+}
+/* { dg-final { scan-tree-dump "x_\[0-9\]+.D. u> y_\[0-9\]+.D.|y_\[0-9\]+.D. u< x_\[0-9\]+.D." "optimized" } } */
+
+_Bool ltne_eq(float z, float w)
+{
+  _Bool c = z < w;
+  _Bool d = z != w;
+  return c == d; // z <= w
+}
+/* { dg-final { scan-tree-dump "z_\[0-9\]+.D. <= w_\[0-9\]+.D.|w_\[0-9\]+.D. >= y_\[0-9\]+.D." "optimized" } } */
+
+_Bool lege_eq(float i, float j)
+{
+  _Bool c = i <= j;
+  _Bool d = i >= j;
+  return c == d; // i u== j
+}
+/* { dg-final { scan-tree-dump "i_\[0-9\]+.D. u== j_\[0-9\]+.D.|j_\[0-9\]+.D. u== i_\[0-9\]+.D." "optimized" } } */
+
+_Bool leeq_eq(float k, float l)
+{
+  _Bool c = k <= l;
+  _Bool d = k == l;
+  return c == d; // k u>= l
+}
+/* { dg-final { scan-tree-dump "k_\[0-9\]+.D. u>= l_\[0-9\]+.D.|l_\[0-9\]+.D. u<= k_\[0-9\]+.D." "optimized" } } */
+
+_Bool lene_eq(float m, float n)
+{
+  _Bool c = m <= n;
+  _Bool d = m != n;
+  return c == d; // m < n
+}
+/* { dg-final { scan-tree-dump "m_\[0-9\]+.D. < n_\[0-9\]+.D.|n_\[0-9\]+.D. > m_\[0-9\]+.D." "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c
new file mode 100644
index 00000000000..00fa7120237
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpxor-2.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fno-trapping-math" } */
+/* PR tree-optimization/107881 */
+
+_Bool ltgtxor(float a, float b)
+{
+  _Bool c = a < b;
+  _Bool d = a > b;
+  return c ^ d; // a <> b
+}
+/* { dg-final { scan-tree-dump "a_\[0-9\]+.D. <> b_\[0-9\]+.D.|b_\[0-9\]+.D. <> a_\[0-9\]+.D." "optimized" } } */
+
+_Bool lteqxor(float x, float y)
+{
+  _Bool c = x < y;
+  _Bool d = x == y;
+  return c ^ d; // x <= y (basically | here)
+}
+/* { dg-final { scan-tree-dump "x_\[0-9\]+.D. <= y_\[0-9\]+.D.|y_\[0-9\]+.D. >= x_\[0-9\]+.D." "optimized" } } */
+
+_Bool ltnexor(float z, float w)
+{
+  _Bool c = z < w;
+  _Bool d = z != w;
+  return c ^ d; // z u> w
+}
+/* { dg-final { scan-tree-dump "z_\[0-9\]+.D. u> w_\[0-9\]+.D.|w_\[0-9\]+.D. u< y_\[0-9\]+.D." "optimized" } } */
+
+_Bool legexor(float i, float j)
+{
+  _Bool c = i <= j;
+  _Bool d = i >= j;
+  return c ^ d; // i <> j
+}
+/* { dg-final { scan-tree-dump "i_\[0-9\]+.D. <> j_\[0-9\]+.D.|j_\[0-9\]+.D. <> i_\[0-9\]+.D." "optimized" } } */
+
+_Bool leeqxor(float k, float l)
+{
+  _Bool c = k <= l;
+  _Bool d = k == l;
+  return c ^ d; // k < l
+}
+/* { dg-final { scan-tree-dump "k_\[0-9\]+.D. < l_\[0-9\]+.D.|l_\[0-9\]+.D. > k_\[0-9\]+.D." "optimized" } } */
+
+_Bool lenexor(float m, float n)
+{
+  _Bool c = m <= n;
+  _Bool d = m != n;
+  return c ^ d; // m u>= n
+}
+/* { dg-final { scan-tree-dump "m_\[0-9\]+.D. u>= n_\[0-9\]+.D.|n_\[0-9\]+.D. u<= m_\[0-9\]+.D." "optimized" } } */
-- 
2.43.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.