public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
@ 2019-06-27  6:12 Li Jia He
  2019-06-27 15:48 ` Jeff Law
  0 siblings, 1 reply; 56+ messages in thread
From: Li Jia He @ 2019-06-27  6:12 UTC (permalink / raw)
  To: gcc-patches; +Cc: segher, wschmidt, rguenther, Li Jia He

Hi,

According to the optimizable case described by Qi Feng on
issue 88784, we can combine the cases into the following:

1. x >  y  &&  x != XXX_MIN  -->   x > y
2. x >  y  &&  x == XXX_MIN  -->   false
3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN

4. x <  y  &&  x != XXX_MAX  -->   x < y
5. x <  y  &&  x == XXX_MAX  -->   false
6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX

7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
8. x <= y  ||  x != XXX_MIN  -->   true
9. x <= y  ||  x == XXX_MIN  -->   x <= y

10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
11. x >= y  ||  x != XXX_MAX  -->   true
12. x >= y  ||  x == XXX_MAX  -->   x >= y

Note: XXX_MIN represents the minimum value of type x.
      XXX_MAX represents the maximum value of type x.

Here we don't need to care about whether the operation is
signed or unsigned.  For example, in the below equation:

'x >  y  &&  x != XXX_MIN  -->   x > y'

If the x type is signed int and XXX_MIN is INT_MIN, we can
optimize it to 'x > y'.  However, if the type of x is unsigned
int and XXX_MIN is 0, we can still optimize it to 'x > y'.

The regression testing for the patch was done on GCC mainline on

    powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions.  Is it OK for trunk ?

Thanks,
Lijia He

gcc/ChangeLog

2019-06-27  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* gimple-fold.c (and_comparisons_contain_equal_operands): New function.
	(and_comparisons_1): Use and_comparisons_contain_equal_operands.
	(or_comparisons_contain_equal_operands): New function.
	(or_comparisons_1): Use or_comparisons_contain_equal_operands.

gcc/testsuite/ChangeLog

2019-06-27  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* gcc.dg/pr88784-1.c: New testcase.
	* gcc.dg/pr88784-2.c: New testcase.
	* gcc.dg/pr88784-3.c: New testcase.
	* gcc.dg/pr88784-4.c: New testcase.
	* gcc.dg/pr88784-5.c: New testcase.
	* gcc.dg/pr88784-6.c: New testcase.
	* gcc.dg/pr88784-7.c: New testcase.
	* gcc.dg/pr88784-8.c: New testcase.
	* gcc.dg/pr88784-9.c: New testcase.
	* gcc.dg/pr88784-10.c: New testcase.
	* gcc.dg/pr88784-11.c: New testcase.
	* gcc.dg/pr88784-12.c: New testcase.
---
 gcc/gimple-fold.c                 | 124 ++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr88784-1.c  |  30 ++++++++
 gcc/testsuite/gcc.dg/pr88784-10.c |  32 ++++++++
 gcc/testsuite/gcc.dg/pr88784-11.c |  30 ++++++++
 gcc/testsuite/gcc.dg/pr88784-12.c |  30 ++++++++
 gcc/testsuite/gcc.dg/pr88784-2.c  |  30 ++++++++
 gcc/testsuite/gcc.dg/pr88784-3.c  |  32 ++++++++
 gcc/testsuite/gcc.dg/pr88784-4.c  |  32 ++++++++
 gcc/testsuite/gcc.dg/pr88784-5.c  |  31 ++++++++
 gcc/testsuite/gcc.dg/pr88784-6.c  |  31 ++++++++
 gcc/testsuite/gcc.dg/pr88784-7.c  |  31 ++++++++
 gcc/testsuite/gcc.dg/pr88784-8.c  |  31 ++++++++
 gcc/testsuite/gcc.dg/pr88784-9.c  |  32 ++++++++
 13 files changed, 496 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-10.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-11.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-12.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-5.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-6.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-7.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-8.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-9.c

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index dfb31a02078..6d2472d2fcb 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5535,6 +5535,62 @@ and_var_with_comparison_1 (gimple *stmt,
   return NULL_TREE;
 }
 
+/* Try to simplify the AND of two comparisons defined by
+   (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
+   This optimization needs to satisfy op1a equal to op2a
+   or op1b equal to op2a.  If this can be done without
+   constructing an intermediate value, return the resulting
+   tree; otherwise NULL_TREE is returned.  */
+
+static tree
+and_comparisons_contain_equal_operands (enum tree_code code1, tree op1a,
+					tree op1b, enum tree_code code2,
+					tree op2a, tree op2b)
+{
+  /* Transform ((Y1 CODE1 X) AND (X CODE2 Y2)) to
+     ((X CODE1' Y1) AND (X CODE2 Y2)).  */
+  if (!operand_equal_p (op1a, op1b, 0) && operand_equal_p (op1b, op2a, 0)
+      && !operand_equal_p (op2a, op2b, 0))
+    return and_comparisons_contain_equal_operands (swap_tree_comparison (code1),
+						   op1b, op1a, code2, op2a,
+						   op2b);
+
+  tree op1a_type = TREE_TYPE (op1a);
+  tree op1b_type = TREE_TYPE (op1b);
+  tree op2b_type = TREE_TYPE (op2b);
+
+  if (INTEGRAL_TYPE_P (op1a_type) && INTEGRAL_TYPE_P (op1b_type)
+      && operand_equal_p (op1a, op2a, 0) && TREE_CODE (op2b) == INTEGER_CST)
+    {
+      if (wi::eq_p (wi::to_wide (op2b), wi::min_value (op2b_type)))
+	{
+	  /* x > y && x != XXX_MIN --> x > y  */
+	  if (code1 == GT_EXPR && code2 == NE_EXPR)
+	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
+	  /* x > y && x == XXX_MIN --> false  */
+	  if (code1 == GT_EXPR && code2 == EQ_EXPR)
+	    return boolean_false_node;
+	  /* x <= y && x == XXX_MIN --> x == XXX_MIN  */
+	  if (code1 == LE_EXPR && code2 == EQ_EXPR)
+	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
+	}
+      else if (wi::eq_p (wi::to_wide (op2b), wi::max_value (op2b_type)))
+	{
+	  /* x < y && x != XXX_MAX --> x < y  */
+	  if (code1 == LT_EXPR && code2 == NE_EXPR)
+	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
+	  /* x < y && x == XXX_MAX --> false  */
+	  if (code1 == LT_EXPR && code2 == EQ_EXPR)
+	    return boolean_false_node;
+	  /* x >= y && x == XXX_MAX --> x == XXX_MAX  */
+	  if (code1 == GE_EXPR && code2 == EQ_EXPR)
+	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons defined by
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
@@ -5546,6 +5602,12 @@ static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
+  /* Try to optimize ((x CODE1 y1) AND (x CODE2 y2))
+     and ((y1 CODE1 x) AND (x CODE2 y2)).  */
+  if (tree t = and_comparisons_contain_equal_operands (code1, op1a, op1b, code2,
+						       op2a, op2b))
+    return t;
+
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) AND (x CODE2 y)).  */
@@ -5999,6 +6061,62 @@ or_var_with_comparison_1 (gimple *stmt,
   return NULL_TREE;
 }
 
+/* Try to simplify the OR of two comparisons defined by
+   (OP1A CODE1 OP1B) or (OP2A CODE2 OP2B), respectively.
+   This optimization needs to satisfy op1a equal to op2a
+   or op1b equal to op2a.  If this can be done without
+   constructing an intermediate value, return the resulting
+   tree; otherwise NULL_TREE is returned.  */
+
+static tree
+or_comparisons_contain_equal_operands (enum tree_code code1, tree op1a,
+				       tree op1b, enum tree_code code2,
+				       tree op2a, tree op2b)
+{
+  /* Transform ((Y1 CODE1 X) OR (X CODE2 Y2)) to
+     ((X CODE1' Y1) OR (X CODE2 Y2)).  */
+  if (!operand_equal_p (op1a, op1b, 0) && operand_equal_p (op1b, op2a, 0)
+      && !operand_equal_p (op2a, op2b, 0))
+    return or_comparisons_contain_equal_operands (swap_tree_comparison (code1),
+						  op1b, op1a, code2, op2a,
+						  op2b);
+
+  tree op1a_type = TREE_TYPE (op1a);
+  tree op1b_type = TREE_TYPE (op1b);
+  tree op2b_type = TREE_TYPE (op2b);
+
+  if (INTEGRAL_TYPE_P (op1a_type) && INTEGRAL_TYPE_P (op1b_type)
+      && operand_equal_p (op1a, op2a, 0) && TREE_CODE (op2b) == INTEGER_CST)
+    {
+      if (wi::eq_p (wi::to_wide (op2b), wi::min_value (op2b_type)))
+	{
+	  /* x > y || x != XXX_MIN --> x != XXX_MIN  */
+	  if (code1 == GT_EXPR && code2 == NE_EXPR)
+	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
+	  /* x <= y || x != XXX_MIN --> true  */
+	  if (code1 == LE_EXPR && code2 == NE_EXPR)
+	    return boolean_true_node;
+	  /* x <= y || x == XXX_MIN --> x <= y  */
+	  if (code1 == LE_EXPR && code2 == EQ_EXPR)
+	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
+	}
+      else if (wi::eq_p (wi::to_wide (op2b), wi::max_value (op2b_type)))
+	{
+	  /* x < y || x != XXX_MAX --> x != XXX_MAX  */
+	  if (code1 == LT_EXPR && code2 == NE_EXPR)
+	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
+	  /* x >= y || x != XXX_MAX --> true  */
+	  if (code1 == GE_EXPR && code2 == NE_EXPR)
+	    return boolean_true_node;
+	  /* x >= y || x == XXX_MAX --> x >= y  */
+	  if (code1 == GE_EXPR && code2 == EQ_EXPR)
+	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the OR of two comparisons defined by
    (OP1A CODE1 OP1B) and (OP2A CODE2 OP2B), respectively.
    If this can be done without constructing an intermediate value,
@@ -6010,6 +6128,12 @@ static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
+  /* Try to optimize ((x CODE1 y1) OR (x CODE2 y2))
+     and ((y1 CODE1 x) OR (x CODE2 y2)).  */
+  if (tree t = or_comparisons_contain_equal_operands (code1, op1a, op1b, code2,
+						      op2a, op2b))
+    return t;
+
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
   /* First check for ((x CODE1 y) OR (x CODE2 y)).  */
diff --git a/gcc/testsuite/gcc.dg/pr88784-1.c b/gcc/testsuite/gcc.dg/pr88784-1.c
new file mode 100644
index 00000000000..067d40d0739
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-10.c b/gcc/testsuite/gcc.dg/pr88784-10.c
new file mode 100644
index 00000000000..fa185d680c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-10.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " <= " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " >= " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-11.c b/gcc/testsuite/gcc.dg/pr88784-11.c
new file mode 100644
index 00000000000..4465910efbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-11.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-12.c b/gcc/testsuite/gcc.dg/pr88784-12.c
new file mode 100644
index 00000000000..477bba07821
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-12.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-2.c b/gcc/testsuite/gcc.dg/pr88784-2.c
new file mode 100644
index 00000000000..265ddc7ceeb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-3.c b/gcc/testsuite/gcc.dg/pr88784-3.c
new file mode 100644
index 00000000000..be2ce315e60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-4.c b/gcc/testsuite/gcc.dg/pr88784-4.c
new file mode 100644
index 00000000000..b927e712464
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-4.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " > " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " < " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-5.c b/gcc/testsuite/gcc.dg/pr88784-5.c
new file mode 100644
index 00000000000..c6a349d7c75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-6.c b/gcc/testsuite/gcc.dg/pr88784-6.c
new file mode 100644
index 00000000000..5b5d2221bf0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-6.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " >= " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-7.c b/gcc/testsuite/gcc.dg/pr88784-7.c
new file mode 100644
index 00000000000..937d2d26593
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-8.c b/gcc/testsuite/gcc.dg/pr88784-8.c
new file mode 100644
index 00000000000..7f5c845eb27
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "dce3" } } */
+/* { dg-final { scan-tree-dump-not " < " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-9.c b/gcc/testsuite/gcc.dg/pr88784-9.c
new file mode 100644
index 00000000000..94f62d94ede
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-9.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
-- 
2.17.1

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-06-27  6:12 [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Li Jia He
@ 2019-06-27 15:48 ` Jeff Law
  2019-06-28  4:55   ` Li Jia He
  0 siblings, 1 reply; 56+ messages in thread
From: Jeff Law @ 2019-06-27 15:48 UTC (permalink / raw)
  To: Li Jia He, gcc-patches; +Cc: segher, wschmidt, rguenther

On 6/27/19 12:11 AM, Li Jia He wrote:
> Hi,
> 
> According to the optimizable case described by Qi Feng on
> issue 88784, we can combine the cases into the following:
> 
> 1. x >  y  &&  x != XXX_MIN  -->   x > y
> 2. x >  y  &&  x == XXX_MIN  -->   false
> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
> 
> 4. x <  y  &&  x != XXX_MAX  -->   x < y
> 5. x <  y  &&  x == XXX_MAX  -->   false
> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
> 
> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
> 8. x <= y  ||  x != XXX_MIN  -->   true
> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
> 
> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
> 11. x >= y  ||  x != XXX_MAX  -->   true
> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
> 
> Note: XXX_MIN represents the minimum value of type x.
>       XXX_MAX represents the maximum value of type x.
> 
> Here we don't need to care about whether the operation is
> signed or unsigned.  For example, in the below equation:
> 
> 'x >  y  &&  x != XXX_MIN  -->   x > y'
> 
> If the x type is signed int and XXX_MIN is INT_MIN, we can
> optimize it to 'x > y'.  However, if the type of x is unsigned
> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
> 
> The regression testing for the patch was done on GCC mainline on
> 
>     powerpc64le-unknown-linux-gnu (Power 9 LE)
> 
> with no regressions.  Is it OK for trunk ?
> 
> Thanks,
> Lijia He
> 
> gcc/ChangeLog
> 
> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
> 	    Qi Feng  <ffengqi@linux.ibm.com>
> 
> 	PR middle-end/88784
> 	* gimple-fold.c (and_comparisons_contain_equal_operands): New function.
> 	(and_comparisons_1): Use and_comparisons_contain_equal_operands.
> 	(or_comparisons_contain_equal_operands): New function.
> 	(or_comparisons_1): Use or_comparisons_contain_equal_operands.
Would this be better done via match.pd?  ISTM this transformation would
be well suited for that framework.

jeff

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-06-27 15:48 ` Jeff Law
@ 2019-06-28  4:55   ` Li Jia He
  2019-06-28 17:02     ` Andrew Pinski
  0 siblings, 1 reply; 56+ messages in thread
From: Li Jia He @ 2019-06-28  4:55 UTC (permalink / raw)
  To: Jeff Law, gcc-patches; +Cc: segher, wschmidt, rguenther



On 2019/6/27 11:48 PM, Jeff Law wrote:
> On 6/27/19 12:11 AM, Li Jia He wrote:
>> Hi,
>>
>> According to the optimizable case described by Qi Feng on
>> issue 88784, we can combine the cases into the following:
>>
>> 1. x >  y  &&  x != XXX_MIN  -->   x > y
>> 2. x >  y  &&  x == XXX_MIN  -->   false
>> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
>>
>> 4. x <  y  &&  x != XXX_MAX  -->   x < y
>> 5. x <  y  &&  x == XXX_MAX  -->   false
>> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
>>
>> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
>> 8. x <= y  ||  x != XXX_MIN  -->   true
>> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
>>
>> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
>> 11. x >= y  ||  x != XXX_MAX  -->   true
>> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
>>
>> Note: XXX_MIN represents the minimum value of type x.
>>        XXX_MAX represents the maximum value of type x.
>>
>> Here we don't need to care about whether the operation is
>> signed or unsigned.  For example, in the below equation:
>>
>> 'x >  y  &&  x != XXX_MIN  -->   x > y'
>>
>> If the x type is signed int and XXX_MIN is INT_MIN, we can
>> optimize it to 'x > y'.  However, if the type of x is unsigned
>> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
>>
>> The regression testing for the patch was done on GCC mainline on
>>
>>      powerpc64le-unknown-linux-gnu (Power 9 LE)
>>
>> with no regressions.  Is it OK for trunk ?
>>
>> Thanks,
>> Lijia He
>>
>> gcc/ChangeLog
>>
>> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
>> 	    Qi Feng  <ffengqi@linux.ibm.com>
>>
>> 	PR middle-end/88784
>> 	* gimple-fold.c (and_comparisons_contain_equal_operands): New function.
>> 	(and_comparisons_1): Use and_comparisons_contain_equal_operands.
>> 	(or_comparisons_contain_equal_operands): New function.
>> 	(or_comparisons_1): Use or_comparisons_contain_equal_operands.
> Would this be better done via match.pd?  ISTM this transformation would
> be well suited for that framework.

Hi, Jeff

I did this because of the following test case:
`
_Bool comp(unsigned x, unsigned y)
{
   return x > y && x != 0;
}
`
The gimple file dumped on the power platform is:
`
comp (unsigned int x, unsigned int y)
{
   _Bool D.2837;
   int iftmp.0;

   if (x > y) goto <D.2841>; else goto <D.2839>;
   <D.2841>:
   if (x != 0) goto <D.2842>; else goto <D.2839>;
   <D.2842>:
   iftmp.0 = 1;
   goto <D.2840>;
   <D.2839>:
   iftmp.0 = 0;
   <D.2840>:
   D.2837 = (_Bool) iftmp.0;
   return D.2837;
}
`
However, the gimple file dumped on x86 is
`
comp (unsigned int x, unsigned int y)
{
   _Bool D.2837;

   _1 = x > y;
   _2 = x != 0;
   _3 = _1 & _2;
   _4 = (int) _3;
   D.2837 = (_Bool) _4;
   return D.2837;
}
`

The reason for the inconsistency between these two behaviors is param
logical-op-non-short-circuit.  If we add the pattern to the match.pd
file, we can only optimize the situation in which the statement is in
the same basic block (logical-op-non-short-circuit=1, x86).  But for
a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
can't handle this situation.

Another reason is that I found out maybe_fold_and_comparisons and
maybe_fold_or_comparisons are not only called by ifcombine pass but
also by reassoc pass. Using this method can basically unify param
logical-op-non-short-circuit=0 or 1.

Thanks,
Lijia He

> 
> jeff
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-06-28  4:55   ` Li Jia He
@ 2019-06-28 17:02     ` Andrew Pinski
  2019-07-01  7:31       ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Andrew Pinski @ 2019-06-28 17:02 UTC (permalink / raw)
  To: Li Jia He
  Cc: Jeff Law, GCC Patches, Segher Boessenkool, wschmidt, Richard Guenther

On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
>
>
>
> On 2019/6/27 11:48 PM, Jeff Law wrote:
> > On 6/27/19 12:11 AM, Li Jia He wrote:
> >> Hi,
> >>
> >> According to the optimizable case described by Qi Feng on
> >> issue 88784, we can combine the cases into the following:
> >>
> >> 1. x >  y  &&  x != XXX_MIN  -->   x > y
> >> 2. x >  y  &&  x == XXX_MIN  -->   false
> >> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
> >>
> >> 4. x <  y  &&  x != XXX_MAX  -->   x < y
> >> 5. x <  y  &&  x == XXX_MAX  -->   false
> >> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
> >>
> >> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
> >> 8. x <= y  ||  x != XXX_MIN  -->   true
> >> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
> >>
> >> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
> >> 11. x >= y  ||  x != XXX_MAX  -->   true
> >> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
> >>
> >> Note: XXX_MIN represents the minimum value of type x.
> >>        XXX_MAX represents the maximum value of type x.
> >>
> >> Here we don't need to care about whether the operation is
> >> signed or unsigned.  For example, in the below equation:
> >>
> >> 'x >  y  &&  x != XXX_MIN  -->   x > y'
> >>
> >> If the x type is signed int and XXX_MIN is INT_MIN, we can
> >> optimize it to 'x > y'.  However, if the type of x is unsigned
> >> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
> >>
> >> The regression testing for the patch was done on GCC mainline on
> >>
> >>      powerpc64le-unknown-linux-gnu (Power 9 LE)
> >>
> >> with no regressions.  Is it OK for trunk ?
> >>
> >> Thanks,
> >> Lijia He
> >>
> >> gcc/ChangeLog
> >>
> >> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
> >>          Qi Feng  <ffengqi@linux.ibm.com>
> >>
> >>      PR middle-end/88784
> >>      * gimple-fold.c (and_comparisons_contain_equal_operands): New function.
> >>      (and_comparisons_1): Use and_comparisons_contain_equal_operands.
> >>      (or_comparisons_contain_equal_operands): New function.
> >>      (or_comparisons_1): Use or_comparisons_contain_equal_operands.
> > Would this be better done via match.pd?  ISTM this transformation would
> > be well suited for that framework.
>
> Hi, Jeff
>
> I did this because of the following test case:
> `
> _Bool comp(unsigned x, unsigned y)
> {
>    return x > y && x != 0;
> }
> `
> The gimple file dumped on the power platform is:
> `
> comp (unsigned int x, unsigned int y)
> {
>    _Bool D.2837;
>    int iftmp.0;
>
>    if (x > y) goto <D.2841>; else goto <D.2839>;
>    <D.2841>:
>    if (x != 0) goto <D.2842>; else goto <D.2839>;
>    <D.2842>:
>    iftmp.0 = 1;
>    goto <D.2840>;
>    <D.2839>:
>    iftmp.0 = 0;
>    <D.2840>:
>    D.2837 = (_Bool) iftmp.0;
>    return D.2837;
> }
> `
> However, the gimple file dumped on x86 is
> `
> comp (unsigned int x, unsigned int y)
> {
>    _Bool D.2837;
>
>    _1 = x > y;
>    _2 = x != 0;
>    _3 = _1 & _2;
>    _4 = (int) _3;
>    D.2837 = (_Bool) _4;
>    return D.2837;
> }
> `
>
> The reason for the inconsistency between these two behaviors is param
> logical-op-non-short-circuit.  If we add the pattern to the match.pd
> file, we can only optimize the situation in which the statement is in
> the same basic block (logical-op-non-short-circuit=1, x86).  But for
> a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
> can't handle this situation.
>
> Another reason is that I found out maybe_fold_and_comparisons and
> maybe_fold_or_comparisons are not only called by ifcombine pass but
> also by reassoc pass. Using this method can basically unify param
> logical-op-non-short-circuit=0 or 1.


As mentioned before ifcombine pass should be using gimple-match
instead of fold_build.  Try converting ifcombine over to gimple-match
infrastructure and add these to match.pd.
NOTE tree-ssa-phiopt should also be moved over to gimple-match but
that is a different issue.


Thanks,
Andrew Pinski

>
> Thanks,
> Lijia He
>
> >
> > jeff
> >
>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-06-28 17:02     ` Andrew Pinski
@ 2019-07-01  7:31       ` Richard Biener
  2019-07-02  7:41         ` Li Jia He
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-07-01  7:31 UTC (permalink / raw)
  To: Andrew Pinski
  Cc: Li Jia He, Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

On Fri, 28 Jun 2019, Andrew Pinski wrote:

> On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
> >
> >
> >
> > On 2019/6/27 11:48 PM, Jeff Law wrote:
> > > On 6/27/19 12:11 AM, Li Jia He wrote:
> > >> Hi,
> > >>
> > >> According to the optimizable case described by Qi Feng on
> > >> issue 88784, we can combine the cases into the following:
> > >>
> > >> 1. x >  y  &&  x != XXX_MIN  -->   x > y
> > >> 2. x >  y  &&  x == XXX_MIN  -->   false
> > >> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
> > >>
> > >> 4. x <  y  &&  x != XXX_MAX  -->   x < y
> > >> 5. x <  y  &&  x == XXX_MAX  -->   false
> > >> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
> > >>
> > >> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
> > >> 8. x <= y  ||  x != XXX_MIN  -->   true
> > >> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
> > >>
> > >> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
> > >> 11. x >= y  ||  x != XXX_MAX  -->   true
> > >> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
> > >>
> > >> Note: XXX_MIN represents the minimum value of type x.
> > >>        XXX_MAX represents the maximum value of type x.
> > >>
> > >> Here we don't need to care about whether the operation is
> > >> signed or unsigned.  For example, in the below equation:
> > >>
> > >> 'x >  y  &&  x != XXX_MIN  -->   x > y'
> > >>
> > >> If the x type is signed int and XXX_MIN is INT_MIN, we can
> > >> optimize it to 'x > y'.  However, if the type of x is unsigned
> > >> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
> > >>
> > >> The regression testing for the patch was done on GCC mainline on
> > >>
> > >>      powerpc64le-unknown-linux-gnu (Power 9 LE)
> > >>
> > >> with no regressions.  Is it OK for trunk ?
> > >>
> > >> Thanks,
> > >> Lijia He
> > >>
> > >> gcc/ChangeLog
> > >>
> > >> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
> > >>          Qi Feng  <ffengqi@linux.ibm.com>
> > >>
> > >>      PR middle-end/88784
> > >>      * gimple-fold.c (and_comparisons_contain_equal_operands): New function.
> > >>      (and_comparisons_1): Use and_comparisons_contain_equal_operands.
> > >>      (or_comparisons_contain_equal_operands): New function.
> > >>      (or_comparisons_1): Use or_comparisons_contain_equal_operands.
> > > Would this be better done via match.pd?  ISTM this transformation would
> > > be well suited for that framework.
> >
> > Hi, Jeff
> >
> > I did this because of the following test case:
> > `
> > _Bool comp(unsigned x, unsigned y)
> > {
> >    return x > y && x != 0;
> > }
> > `
> > The gimple file dumped on the power platform is:
> > `
> > comp (unsigned int x, unsigned int y)
> > {
> >    _Bool D.2837;
> >    int iftmp.0;
> >
> >    if (x > y) goto <D.2841>; else goto <D.2839>;
> >    <D.2841>:
> >    if (x != 0) goto <D.2842>; else goto <D.2839>;
> >    <D.2842>:
> >    iftmp.0 = 1;
> >    goto <D.2840>;
> >    <D.2839>:
> >    iftmp.0 = 0;
> >    <D.2840>:
> >    D.2837 = (_Bool) iftmp.0;
> >    return D.2837;
> > }
> > `
> > However, the gimple file dumped on x86 is
> > `
> > comp (unsigned int x, unsigned int y)
> > {
> >    _Bool D.2837;
> >
> >    _1 = x > y;
> >    _2 = x != 0;
> >    _3 = _1 & _2;
> >    _4 = (int) _3;
> >    D.2837 = (_Bool) _4;
> >    return D.2837;
> > }
> > `
> >
> > The reason for the inconsistency between these two behaviors is param
> > logical-op-non-short-circuit.  If we add the pattern to the match.pd
> > file, we can only optimize the situation in which the statement is in
> > the same basic block (logical-op-non-short-circuit=1, x86).  But for
> > a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
> > can't handle this situation.
> >
> > Another reason is that I found out maybe_fold_and_comparisons and
> > maybe_fold_or_comparisons are not only called by ifcombine pass but
> > also by reassoc pass. Using this method can basically unify param
> > logical-op-non-short-circuit=0 or 1.
> 
> 
> As mentioned before ifcombine pass should be using gimple-match
> instead of fold_build.  Try converting ifcombine over to gimple-match
> infrastructure and add these to match.pd.

Yes, I mentioned that in the PR.  The issue is that at the moment
to combine x > y with x <= y you'd have to build GENERIC trees
for both or temporary GIMPLE assign with a SSA def (and then feed
that into the GENERIC or GIMPLE match.pd path).

maybe_fold_and/or_comparisons handle two exploded binary expressions
while the current match.pd entries handle at most one exploded one
(the outermost then, either AND or OR).  But it would be definitely
doable to auto-generate maybe_fold_and/or_comparisons from match.pd
patterns which is what I'd ultimatively suggest to do (in some more
generalized form maybe).  Either with a separate genmatch invocation
or as part of the --gimple processing (not sure what is more feasible
here).

I told Li Jia He that I don't expect him to do this work.

Note I didn't review the actual patch yet.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-01  7:31       ` Richard Biener
@ 2019-07-02  7:41         ` Li Jia He
  2019-07-02  8:09           ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Li Jia He @ 2019-07-02  7:41 UTC (permalink / raw)
  To: Richard Biener, Andrew Pinski
  Cc: Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

[-- Attachment #1: Type: text/plain, Size: 5271 bytes --]



On 2019/7/1 3:30 PM, Richard Biener wrote:
> On Fri, 28 Jun 2019, Andrew Pinski wrote:
> 
>> On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
>>>
>>>
>>>
>>> On 2019/6/27 11:48 PM, Jeff Law wrote:
>>>> On 6/27/19 12:11 AM, Li Jia He wrote:
>>>>> Hi,
>>>>>
>>>>> According to the optimizable case described by Qi Feng on
>>>>> issue 88784, we can combine the cases into the following:
>>>>>
>>>>> 1. x >  y  &&  x != XXX_MIN  -->   x > y
>>>>> 2. x >  y  &&  x == XXX_MIN  -->   false
>>>>> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
>>>>>
>>>>> 4. x <  y  &&  x != XXX_MAX  -->   x < y
>>>>> 5. x <  y  &&  x == XXX_MAX  -->   false
>>>>> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
>>>>>
>>>>> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
>>>>> 8. x <= y  ||  x != XXX_MIN  -->   true
>>>>> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
>>>>>
>>>>> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
>>>>> 11. x >= y  ||  x != XXX_MAX  -->   true
>>>>> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
>>>>>
>>>>> Note: XXX_MIN represents the minimum value of type x.
>>>>>         XXX_MAX represents the maximum value of type x.
>>>>>
>>>>> Here we don't need to care about whether the operation is
>>>>> signed or unsigned.  For example, in the below equation:
>>>>>
>>>>> 'x >  y  &&  x != XXX_MIN  -->   x > y'
>>>>>
>>>>> If the x type is signed int and XXX_MIN is INT_MIN, we can
>>>>> optimize it to 'x > y'.  However, if the type of x is unsigned
>>>>> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
>>>>>
>>>>> The regression testing for the patch was done on GCC mainline on
>>>>>
>>>>>       powerpc64le-unknown-linux-gnu (Power 9 LE)
>>>>>
>>>>> with no regressions.  Is it OK for trunk ?
>>>>>
>>>>> Thanks,
>>>>> Lijia He
>>>>>
>>>>> gcc/ChangeLog
>>>>>
>>>>> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
>>>>>           Qi Feng  <ffengqi@linux.ibm.com>
>>>>>
>>>>>       PR middle-end/88784
>>>>>       * gimple-fold.c (and_comparisons_contain_equal_operands): New function.
>>>>>       (and_comparisons_1): Use and_comparisons_contain_equal_operands.
>>>>>       (or_comparisons_contain_equal_operands): New function.
>>>>>       (or_comparisons_1): Use or_comparisons_contain_equal_operands.
>>>> Would this be better done via match.pd?  ISTM this transformation would
>>>> be well suited for that framework.
>>>
>>> Hi, Jeff
>>>
>>> I did this because of the following test case:
>>> `
>>> _Bool comp(unsigned x, unsigned y)
>>> {
>>>     return x > y && x != 0;
>>> }
>>> `
>>> The gimple file dumped on the power platform is:
>>> `
>>> comp (unsigned int x, unsigned int y)
>>> {
>>>     _Bool D.2837;
>>>     int iftmp.0;
>>>
>>>     if (x > y) goto <D.2841>; else goto <D.2839>;
>>>     <D.2841>:
>>>     if (x != 0) goto <D.2842>; else goto <D.2839>;
>>>     <D.2842>:
>>>     iftmp.0 = 1;
>>>     goto <D.2840>;
>>>     <D.2839>:
>>>     iftmp.0 = 0;
>>>     <D.2840>:
>>>     D.2837 = (_Bool) iftmp.0;
>>>     return D.2837;
>>> }
>>> `
>>> However, the gimple file dumped on x86 is
>>> `
>>> comp (unsigned int x, unsigned int y)
>>> {
>>>     _Bool D.2837;
>>>
>>>     _1 = x > y;
>>>     _2 = x != 0;
>>>     _3 = _1 & _2;
>>>     _4 = (int) _3;
>>>     D.2837 = (_Bool) _4;
>>>     return D.2837;
>>> }
>>> `
>>>
>>> The reason for the inconsistency between these two behaviors is param
>>> logical-op-non-short-circuit.  If we add the pattern to the match.pd
>>> file, we can only optimize the situation in which the statement is in
>>> the same basic block (logical-op-non-short-circuit=1, x86).  But for
>>> a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
>>> can't handle this situation.
>>>
>>> Another reason is that I found out maybe_fold_and_comparisons and
>>> maybe_fold_or_comparisons are not only called by ifcombine pass but
>>> also by reassoc pass. Using this method can basically unify param
>>> logical-op-non-short-circuit=0 or 1.
>>
>>
>> As mentioned before ifcombine pass should be using gimple-match
>> instead of fold_build.  Try converting ifcombine over to gimple-match
>> infrastructure and add these to match.pd.
> 
> Yes, I mentioned that in the PR.  The issue is that at the moment
> to combine x > y with x <= y you'd have to build GENERIC trees
> for both or temporary GIMPLE assign with a SSA def (and then feed
> that into the GENERIC or GIMPLE match.pd path).

Hi,

I did some experimentation using ‘temporary GIMPLE with a SSA def (and 
then feed that into the GIMPLE match.pd path’.  Could we consider the 
code in the attachment(I did a test and the code took effect)?

Thanks,
Lijia He

> 
> maybe_fold_and/or_comparisons handle two exploded binary expressions
> while the current match.pd entries handle at most one exploded one
> (the outermost then, either AND or OR).  But it would be definitely
> doable to auto-generate maybe_fold_and/or_comparisons from match.pd
> patterns which is what I'd ultimatively suggest to do (in some more
> generalized form maybe).  Either with a separate genmatch invocation
> or as part of the --gimple processing (not sure what is more feasible
> here).
> 
> I told Li Jia He that I don't expect him to do this work.
> 
> Note I didn't review the actual patch yet.
> 
> Thanks,
> Richard.
> 

[-- Attachment #2: match.diff --]
[-- Type: text/plain, Size: 5980 bytes --]

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index dfb31a02078..9974b491626 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5789,6 +5789,12 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+static tree
+do_valueize (tree t)
+{
+  return t;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5800,11 +5806,39 @@ tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
+  tree t1 = fold_build2 (code1, boolean_type_node, op1a, op1b);
+  tree t2 = fold_build2 (code2, boolean_type_node, op2a, op2b);
+
+  tree new_lhs1 = make_ssa_name (TREE_TYPE (t1));
+  tree new_lhs2 = make_ssa_name (TREE_TYPE (t2));
+
+  gassign *gassign1 = gimple_build_assign (new_lhs1, t1);
+  gassign *gassign2 = gimple_build_assign (new_lhs2, t2);
+
+  tree t = gimple_simplify (TRUTH_AND_EXPR, boolean_type_node,
+			    gimple_assign_lhs (gassign1),
+			    gimple_assign_lhs (gassign2), NULL, do_valueize);
+
+  if (!t)
+    {
+      t = gimple_simplify (TRUTH_AND_EXPR, boolean_type_node,
+			   gimple_assign_lhs (gassign2),
+			   gimple_assign_lhs (gassign1), NULL, do_valueize);
+    }
+
   if (t)
-    return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+    {
+      gimple *def = SSA_NAME_DEF_STMT (t);
+
+      if (!is_gimple_assign (def)
+	  || TREE_CODE_CLASS (gimple_assign_rhs_code (def)) != tcc_comparison)
+	return NULL_TREE;
+
+      return fold_build2 (gimple_assign_rhs_code (def), boolean_type_node,
+			  gimple_assign_rhs1 (def), gimple_assign_rhs2 (def));
+    }
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
diff --git a/gcc/match.pd b/gcc/match.pd
index f8e35e96d22..21a147d0ff1 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1859,6 +1859,101 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     { wide_int_to_tree (type, (wi::to_wide (@1)
 			       & (bitpos / BITS_PER_UNIT))); }))))
 
+/* x >  y  &&  x != XXX_MIN  -->  x > y  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x >  y  &&  x == XXX_MIN  -->  false  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    { boolean_false_node; })))
+
+/* x <=  y  &&  x == XXX_MIN  -->  x == XXX_MIN  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (le:c @0 @1) (eq@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x <  y  &&  x != XXX_MAX  -->  x < y  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (lt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x <  y  &&  x == XXX_MAX  -->  false  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (lt:c @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    { boolean_false_node; })))
+
+/* x >=  y  &&  x == XXX_MAX  -->  x == XXX_MAX  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (ge:c @0 @1) (eq@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x >  y  ||  x != XXX_MIN   -->  x != XXX_MIN  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (gt:c @0 @1) (ne@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x <=  y  ||  x != XXX_MIN   -->  true  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    { boolean_true_node; })))
+
+/* x <=  y  ||  x == XXX_MIN   -->  x <= y  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c@3 @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x <  y  ||  x != XXX_MAX   -->  x != XXX_MAX  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (lt:c @0 @1) (ne@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x >=  y  ||  x != XXX_MAX   -->  true  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (ge:c @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    { boolean_true_node; })))
+
+/* x >=  y  ||  x == XXX_MAX   -->  x >= y  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (ge:c@3 @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    @3)))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-02  7:41         ` Li Jia He
@ 2019-07-02  8:09           ` Richard Biener
  2019-07-02  8:51             ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-07-02  8:09 UTC (permalink / raw)
  To: Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

[-- Attachment #1: Type: text/plain, Size: 6639 bytes --]

On Tue, 2 Jul 2019, Li Jia He wrote:

> 
> 
> On 2019/7/1 3:30 PM, Richard Biener wrote:
> > On Fri, 28 Jun 2019, Andrew Pinski wrote:
> > 
> > > On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
> > > > 
> > > > 
> > > > 
> > > > On 2019/6/27 11:48 PM, Jeff Law wrote:
> > > > > On 6/27/19 12:11 AM, Li Jia He wrote:
> > > > > > Hi,
> > > > > > 
> > > > > > According to the optimizable case described by Qi Feng on
> > > > > > issue 88784, we can combine the cases into the following:
> > > > > > 
> > > > > > 1. x >  y  &&  x != XXX_MIN  -->   x > y
> > > > > > 2. x >  y  &&  x == XXX_MIN  -->   false
> > > > > > 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
> > > > > > 
> > > > > > 4. x <  y  &&  x != XXX_MAX  -->   x < y
> > > > > > 5. x <  y  &&  x == XXX_MAX  -->   false
> > > > > > 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
> > > > > > 
> > > > > > 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
> > > > > > 8. x <= y  ||  x != XXX_MIN  -->   true
> > > > > > 9. x <= y  ||  x == XXX_MIN  -->   x <= y
> > > > > > 
> > > > > > 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
> > > > > > 11. x >= y  ||  x != XXX_MAX  -->   true
> > > > > > 12. x >= y  ||  x == XXX_MAX  -->   x >= y
> > > > > > 
> > > > > > Note: XXX_MIN represents the minimum value of type x.
> > > > > >         XXX_MAX represents the maximum value of type x.
> > > > > > 
> > > > > > Here we don't need to care about whether the operation is
> > > > > > signed or unsigned.  For example, in the below equation:
> > > > > > 
> > > > > > 'x >  y  &&  x != XXX_MIN  -->   x > y'
> > > > > > 
> > > > > > If the x type is signed int and XXX_MIN is INT_MIN, we can
> > > > > > optimize it to 'x > y'.  However, if the type of x is unsigned
> > > > > > int and XXX_MIN is 0, we can still optimize it to 'x > y'.
> > > > > > 
> > > > > > The regression testing for the patch was done on GCC mainline on
> > > > > > 
> > > > > >       powerpc64le-unknown-linux-gnu (Power 9 LE)
> > > > > > 
> > > > > > with no regressions.  Is it OK for trunk ?
> > > > > > 
> > > > > > Thanks,
> > > > > > Lijia He
> > > > > > 
> > > > > > gcc/ChangeLog
> > > > > > 
> > > > > > 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
> > > > > >           Qi Feng  <ffengqi@linux.ibm.com>
> > > > > > 
> > > > > >       PR middle-end/88784
> > > > > >       * gimple-fold.c (and_comparisons_contain_equal_operands): New
> > > > > > function.
> > > > > >       (and_comparisons_1): Use
> > > > > > and_comparisons_contain_equal_operands.
> > > > > >       (or_comparisons_contain_equal_operands): New function.
> > > > > >       (or_comparisons_1): Use or_comparisons_contain_equal_operands.
> > > > > Would this be better done via match.pd?  ISTM this transformation
> > > > > would
> > > > > be well suited for that framework.
> > > > 
> > > > Hi, Jeff
> > > > 
> > > > I did this because of the following test case:
> > > > `
> > > > _Bool comp(unsigned x, unsigned y)
> > > > {
> > > >     return x > y && x != 0;
> > > > }
> > > > `
> > > > The gimple file dumped on the power platform is:
> > > > `
> > > > comp (unsigned int x, unsigned int y)
> > > > {
> > > >     _Bool D.2837;
> > > >     int iftmp.0;
> > > > 
> > > >     if (x > y) goto <D.2841>; else goto <D.2839>;
> > > >     <D.2841>:
> > > >     if (x != 0) goto <D.2842>; else goto <D.2839>;
> > > >     <D.2842>:
> > > >     iftmp.0 = 1;
> > > >     goto <D.2840>;
> > > >     <D.2839>:
> > > >     iftmp.0 = 0;
> > > >     <D.2840>:
> > > >     D.2837 = (_Bool) iftmp.0;
> > > >     return D.2837;
> > > > }
> > > > `
> > > > However, the gimple file dumped on x86 is
> > > > `
> > > > comp (unsigned int x, unsigned int y)
> > > > {
> > > >     _Bool D.2837;
> > > > 
> > > >     _1 = x > y;
> > > >     _2 = x != 0;
> > > >     _3 = _1 & _2;
> > > >     _4 = (int) _3;
> > > >     D.2837 = (_Bool) _4;
> > > >     return D.2837;
> > > > }
> > > > `
> > > > 
> > > > The reason for the inconsistency between these two behaviors is param
> > > > logical-op-non-short-circuit.  If we add the pattern to the match.pd
> > > > file, we can only optimize the situation in which the statement is in
> > > > the same basic block (logical-op-non-short-circuit=1, x86).  But for
> > > > a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
> > > > can't handle this situation.
> > > > 
> > > > Another reason is that I found out maybe_fold_and_comparisons and
> > > > maybe_fold_or_comparisons are not only called by ifcombine pass but
> > > > also by reassoc pass. Using this method can basically unify param
> > > > logical-op-non-short-circuit=0 or 1.
> > > 
> > > 
> > > As mentioned before ifcombine pass should be using gimple-match
> > > instead of fold_build.  Try converting ifcombine over to gimple-match
> > > infrastructure and add these to match.pd.
> > 
> > Yes, I mentioned that in the PR.  The issue is that at the moment
> > to combine x > y with x <= y you'd have to build GENERIC trees
> > for both or temporary GIMPLE assign with a SSA def (and then feed
> > that into the GENERIC or GIMPLE match.pd path).
> 
> Hi,
> 
> I did some experimentation using ‘temporary GIMPLE with a SSA def (and then
> feed that into the GIMPLE match.pd path’.  Could we consider the code in the
> attachment(I did a test and the code took effect)?

No, that's excessive overhead IMHO - the whole point of these functions
originally was to avoid build2 (...) on both conditionals.  If we
now create two SSA names and two GIMPLE statements that's too much.

As said it shouldn't be rocket science to teach genmatch to
auto-generate those functions from match.pd patterns but it certainly
is some work (less so for somebody with genmatch knowledge).
I'll give it a poke...

Richard.

> Thanks,
> Lijia He
> 
> > 
> > maybe_fold_and/or_comparisons handle two exploded binary expressions
> > while the current match.pd entries handle at most one exploded one
> > (the outermost then, either AND or OR).  But it would be definitely
> > doable to auto-generate maybe_fold_and/or_comparisons from match.pd
> > patterns which is what I'd ultimatively suggest to do (in some more
> > generalized form maybe).  Either with a separate genmatch invocation
> > or as part of the --gimple processing (not sure what is more feasible
> > here).
> > 
> > I told Li Jia He that I don't expect him to do this work.
> > 
> > Note I didn't review the actual patch yet.
> > 
> > Thanks,
> > Richard.
> > 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany;
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah; HRB 21284 (AG Nürnberg)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-02  8:09           ` Richard Biener
@ 2019-07-02  8:51             ` Richard Biener
  2019-07-16  6:54               ` Li Jia He
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-07-02  8:51 UTC (permalink / raw)
  To: Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

[-- Attachment #1: Type: text/plain, Size: 8595 bytes --]

On Tue, 2 Jul 2019, Richard Biener wrote:

> On Tue, 2 Jul 2019, Li Jia He wrote:
> 
> > 
> > 
> > On 2019/7/1 3:30 PM, Richard Biener wrote:
> > > On Fri, 28 Jun 2019, Andrew Pinski wrote:
> > > 
> > > > On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
> > > > > 
> > > > > 
> > > > > 
> > > > > On 2019/6/27 11:48 PM, Jeff Law wrote:
> > > > > > On 6/27/19 12:11 AM, Li Jia He wrote:
> > > > > > > Hi,
> > > > > > > 
> > > > > > > According to the optimizable case described by Qi Feng on
> > > > > > > issue 88784, we can combine the cases into the following:
> > > > > > > 
> > > > > > > 1. x >  y  &&  x != XXX_MIN  -->   x > y
> > > > > > > 2. x >  y  &&  x == XXX_MIN  -->   false
> > > > > > > 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
> > > > > > > 
> > > > > > > 4. x <  y  &&  x != XXX_MAX  -->   x < y
> > > > > > > 5. x <  y  &&  x == XXX_MAX  -->   false
> > > > > > > 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
> > > > > > > 
> > > > > > > 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
> > > > > > > 8. x <= y  ||  x != XXX_MIN  -->   true
> > > > > > > 9. x <= y  ||  x == XXX_MIN  -->   x <= y
> > > > > > > 
> > > > > > > 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
> > > > > > > 11. x >= y  ||  x != XXX_MAX  -->   true
> > > > > > > 12. x >= y  ||  x == XXX_MAX  -->   x >= y
> > > > > > > 
> > > > > > > Note: XXX_MIN represents the minimum value of type x.
> > > > > > >         XXX_MAX represents the maximum value of type x.
> > > > > > > 
> > > > > > > Here we don't need to care about whether the operation is
> > > > > > > signed or unsigned.  For example, in the below equation:
> > > > > > > 
> > > > > > > 'x >  y  &&  x != XXX_MIN  -->   x > y'
> > > > > > > 
> > > > > > > If the x type is signed int and XXX_MIN is INT_MIN, we can
> > > > > > > optimize it to 'x > y'.  However, if the type of x is unsigned
> > > > > > > int and XXX_MIN is 0, we can still optimize it to 'x > y'.
> > > > > > > 
> > > > > > > The regression testing for the patch was done on GCC mainline on
> > > > > > > 
> > > > > > >       powerpc64le-unknown-linux-gnu (Power 9 LE)
> > > > > > > 
> > > > > > > with no regressions.  Is it OK for trunk ?
> > > > > > > 
> > > > > > > Thanks,
> > > > > > > Lijia He
> > > > > > > 
> > > > > > > gcc/ChangeLog
> > > > > > > 
> > > > > > > 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
> > > > > > >           Qi Feng  <ffengqi@linux.ibm.com>
> > > > > > > 
> > > > > > >       PR middle-end/88784
> > > > > > >       * gimple-fold.c (and_comparisons_contain_equal_operands): New
> > > > > > > function.
> > > > > > >       (and_comparisons_1): Use
> > > > > > > and_comparisons_contain_equal_operands.
> > > > > > >       (or_comparisons_contain_equal_operands): New function.
> > > > > > >       (or_comparisons_1): Use or_comparisons_contain_equal_operands.
> > > > > > Would this be better done via match.pd?  ISTM this transformation
> > > > > > would
> > > > > > be well suited for that framework.
> > > > > 
> > > > > Hi, Jeff
> > > > > 
> > > > > I did this because of the following test case:
> > > > > `
> > > > > _Bool comp(unsigned x, unsigned y)
> > > > > {
> > > > >     return x > y && x != 0;
> > > > > }
> > > > > `
> > > > > The gimple file dumped on the power platform is:
> > > > > `
> > > > > comp (unsigned int x, unsigned int y)
> > > > > {
> > > > >     _Bool D.2837;
> > > > >     int iftmp.0;
> > > > > 
> > > > >     if (x > y) goto <D.2841>; else goto <D.2839>;
> > > > >     <D.2841>:
> > > > >     if (x != 0) goto <D.2842>; else goto <D.2839>;
> > > > >     <D.2842>:
> > > > >     iftmp.0 = 1;
> > > > >     goto <D.2840>;
> > > > >     <D.2839>:
> > > > >     iftmp.0 = 0;
> > > > >     <D.2840>:
> > > > >     D.2837 = (_Bool) iftmp.0;
> > > > >     return D.2837;
> > > > > }
> > > > > `
> > > > > However, the gimple file dumped on x86 is
> > > > > `
> > > > > comp (unsigned int x, unsigned int y)
> > > > > {
> > > > >     _Bool D.2837;
> > > > > 
> > > > >     _1 = x > y;
> > > > >     _2 = x != 0;
> > > > >     _3 = _1 & _2;
> > > > >     _4 = (int) _3;
> > > > >     D.2837 = (_Bool) _4;
> > > > >     return D.2837;
> > > > > }
> > > > > `
> > > > > 
> > > > > The reason for the inconsistency between these two behaviors is param
> > > > > logical-op-non-short-circuit.  If we add the pattern to the match.pd
> > > > > file, we can only optimize the situation in which the statement is in
> > > > > the same basic block (logical-op-non-short-circuit=1, x86).  But for
> > > > > a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
> > > > > can't handle this situation.
> > > > > 
> > > > > Another reason is that I found out maybe_fold_and_comparisons and
> > > > > maybe_fold_or_comparisons are not only called by ifcombine pass but
> > > > > also by reassoc pass. Using this method can basically unify param
> > > > > logical-op-non-short-circuit=0 or 1.
> > > > 
> > > > 
> > > > As mentioned before ifcombine pass should be using gimple-match
> > > > instead of fold_build.  Try converting ifcombine over to gimple-match
> > > > infrastructure and add these to match.pd.
> > > 
> > > Yes, I mentioned that in the PR.  The issue is that at the moment
> > > to combine x > y with x <= y you'd have to build GENERIC trees
> > > for both or temporary GIMPLE assign with a SSA def (and then feed
> > > that into the GENERIC or GIMPLE match.pd path).
> > 
> > Hi,
> > 
> > I did some experimentation using ‘temporary GIMPLE with a SSA def (and then
> > feed that into the GIMPLE match.pd path’.  Could we consider the code in the
> > attachment(I did a test and the code took effect)?
> 
> No, that's excessive overhead IMHO - the whole point of these functions
> originally was to avoid build2 (...) on both conditionals.  If we
> now create two SSA names and two GIMPLE statements that's too much.
> 
> As said it shouldn't be rocket science to teach genmatch to
> auto-generate those functions from match.pd patterns but it certainly
> is some work (less so for somebody with genmatch knowledge).
> I'll give it a poke...

OK, it's not so easy.  I guess we could lower the cost of building
SSA names / gimple stmts significantly if we allocated them on the
stack like via

gimple *stmt1 = XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN) + 2 * 
sizeof (tree));
memset (stmt1, 0, ...);
gimple_set_code (stmt1, GIMPLE_ASSIGN);
gimple_set_num_ops (stmt1, 3);
gimple_init_singleton (stmt1);

gimple_stmt_iterator gsi = gsi_for_stmt (stmt1);
gimple_assign_set_rhs_with_ops (&gsi, actual operation...);

tree lhs1 = XALLOCA (tree_ssa_name);
memset (lhs1, 0, sizeof (tree_ssa_name));
TREE_SET_CODE (lhs1, SSA_NAME);
TREE_TYPE (lhs1) = ...;

gimple_assing_set_lhs (stmt1, lhs1);

it's all a bit ugly and some factoring in the generic gimple machinery
might easen this kind of hacks, but well...

With the above you could then use

  gimple_match_op op (gimple_match_cond::UNCOND, BIT_AND_EXPR /* or OR */,
		      boolean_type_node, lhs1, lhs2);
  if (gimple_resimplify2 (NULL, &op, follow_all_ssa_edges))
    ... successfully simplified into 'op' ...

with the simplification path then extracting the simplified result
from 'op'.  Note this deliberately leaves out passing a gimple_seq
as storage for more complex simplification results to match
existing behavior.

Your patch has the GC allocation and SSA name (and namespace!)
allocation overhead and most definitely misses releasing the
SSA names you allocated.

Note with the above hack the simplified result has to be checked
for mentions of lhs1 or lhs2 - a case we have to reject because
their definitions are transitional.

Richard.

> Richard.
> 
> > Thanks,
> > Lijia He
> > 
> > > 
> > > maybe_fold_and/or_comparisons handle two exploded binary expressions
> > > while the current match.pd entries handle at most one exploded one
> > > (the outermost then, either AND or OR).  But it would be definitely
> > > doable to auto-generate maybe_fold_and/or_comparisons from match.pd
> > > patterns which is what I'd ultimatively suggest to do (in some more
> > > generalized form maybe).  Either with a separate genmatch invocation
> > > or as part of the --gimple processing (not sure what is more feasible
> > > here).
> > > 
> > > I told Li Jia He that I don't expect him to do this work.
> > > 
> > > Note I didn't review the actual patch yet.
> > > 
> > > Thanks,
> > > Richard.
> > > 
> > 
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Linux GmbH, Maxfeldstrasse 5, 90409 Nuernberg, Germany;
GF: Felix Imendörffer, Mary Higgins, Sri Rasiah; HRB 21284 (AG Nürnberg)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-02  8:51             ` Richard Biener
@ 2019-07-16  6:54               ` Li Jia He
  2019-08-30 11:16                 ` Martin Liška
                                   ` (2 more replies)
  0 siblings, 3 replies; 56+ messages in thread
From: Li Jia He @ 2019-07-16  6:54 UTC (permalink / raw)
  To: Richard Biener
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

[-- Attachment #1: Type: text/plain, Size: 8725 bytes --]



On 2019/7/2 4:51 PM, Richard Biener wrote:
> On Tue, 2 Jul 2019, Richard Biener wrote:
> 
>> On Tue, 2 Jul 2019, Li Jia He wrote:
>>
>>>
>>>
>>> On 2019/7/1 3:30 PM, Richard Biener wrote:
>>>> On Fri, 28 Jun 2019, Andrew Pinski wrote:
>>>>
>>>>> On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 2019/6/27 11:48 PM, Jeff Law wrote:
>>>>>>> On 6/27/19 12:11 AM, Li Jia He wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> According to the optimizable case described by Qi Feng on
>>>>>>>> issue 88784, we can combine the cases into the following:
>>>>>>>>
>>>>>>>> 1. x >  y  &&  x != XXX_MIN  -->   x > y
>>>>>>>> 2. x >  y  &&  x == XXX_MIN  -->   false
>>>>>>>> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
>>>>>>>>
>>>>>>>> 4. x <  y  &&  x != XXX_MAX  -->   x < y
>>>>>>>> 5. x <  y  &&  x == XXX_MAX  -->   false
>>>>>>>> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
>>>>>>>>
>>>>>>>> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
>>>>>>>> 8. x <= y  ||  x != XXX_MIN  -->   true
>>>>>>>> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
>>>>>>>>
>>>>>>>> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
>>>>>>>> 11. x >= y  ||  x != XXX_MAX  -->   true
>>>>>>>> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
>>>>>>>>
>>>>>>>> Note: XXX_MIN represents the minimum value of type x.
>>>>>>>>          XXX_MAX represents the maximum value of type x.
>>>>>>>>
>>>>>>>> Here we don't need to care about whether the operation is
>>>>>>>> signed or unsigned.  For example, in the below equation:
>>>>>>>>
>>>>>>>> 'x >  y  &&  x != XXX_MIN  -->   x > y'
>>>>>>>>
>>>>>>>> If the x type is signed int and XXX_MIN is INT_MIN, we can
>>>>>>>> optimize it to 'x > y'.  However, if the type of x is unsigned
>>>>>>>> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
>>>>>>>>
>>>>>>>> The regression testing for the patch was done on GCC mainline on
>>>>>>>>
>>>>>>>>        powerpc64le-unknown-linux-gnu (Power 9 LE)
>>>>>>>>
>>>>>>>> with no regressions.  Is it OK for trunk ?
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Lijia He
>>>>>>>>
>>>>>>>> gcc/ChangeLog
>>>>>>>>
>>>>>>>> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
>>>>>>>>            Qi Feng  <ffengqi@linux.ibm.com>
>>>>>>>>
>>>>>>>>        PR middle-end/88784
>>>>>>>>        * gimple-fold.c (and_comparisons_contain_equal_operands): New
>>>>>>>> function.
>>>>>>>>        (and_comparisons_1): Use
>>>>>>>> and_comparisons_contain_equal_operands.
>>>>>>>>        (or_comparisons_contain_equal_operands): New function.
>>>>>>>>        (or_comparisons_1): Use or_comparisons_contain_equal_operands.
>>>>>>> Would this be better done via match.pd?  ISTM this transformation
>>>>>>> would
>>>>>>> be well suited for that framework.
>>>>>>
>>>>>> Hi, Jeff
>>>>>>
>>>>>> I did this because of the following test case:
>>>>>> `
>>>>>> _Bool comp(unsigned x, unsigned y)
>>>>>> {
>>>>>>      return x > y && x != 0;
>>>>>> }
>>>>>> `
>>>>>> The gimple file dumped on the power platform is:
>>>>>> `
>>>>>> comp (unsigned int x, unsigned int y)
>>>>>> {
>>>>>>      _Bool D.2837;
>>>>>>      int iftmp.0;
>>>>>>
>>>>>>      if (x > y) goto <D.2841>; else goto <D.2839>;
>>>>>>      <D.2841>:
>>>>>>      if (x != 0) goto <D.2842>; else goto <D.2839>;
>>>>>>      <D.2842>:
>>>>>>      iftmp.0 = 1;
>>>>>>      goto <D.2840>;
>>>>>>      <D.2839>:
>>>>>>      iftmp.0 = 0;
>>>>>>      <D.2840>:
>>>>>>      D.2837 = (_Bool) iftmp.0;
>>>>>>      return D.2837;
>>>>>> }
>>>>>> `
>>>>>> However, the gimple file dumped on x86 is
>>>>>> `
>>>>>> comp (unsigned int x, unsigned int y)
>>>>>> {
>>>>>>      _Bool D.2837;
>>>>>>
>>>>>>      _1 = x > y;
>>>>>>      _2 = x != 0;
>>>>>>      _3 = _1 & _2;
>>>>>>      _4 = (int) _3;
>>>>>>      D.2837 = (_Bool) _4;
>>>>>>      return D.2837;
>>>>>> }
>>>>>> `
>>>>>>
>>>>>> The reason for the inconsistency between these two behaviors is param
>>>>>> logical-op-non-short-circuit.  If we add the pattern to the match.pd
>>>>>> file, we can only optimize the situation in which the statement is in
>>>>>> the same basic block (logical-op-non-short-circuit=1, x86).  But for
>>>>>> a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
>>>>>> can't handle this situation.
>>>>>>
>>>>>> Another reason is that I found out maybe_fold_and_comparisons and
>>>>>> maybe_fold_or_comparisons are not only called by ifcombine pass but
>>>>>> also by reassoc pass. Using this method can basically unify param
>>>>>> logical-op-non-short-circuit=0 or 1.
>>>>>
>>>>>
>>>>> As mentioned before ifcombine pass should be using gimple-match
>>>>> instead of fold_build.  Try converting ifcombine over to gimple-match
>>>>> infrastructure and add these to match.pd.
>>>>
>>>> Yes, I mentioned that in the PR.  The issue is that at the moment
>>>> to combine x > y with x <= y you'd have to build GENERIC trees
>>>> for both or temporary GIMPLE assign with a SSA def (and then feed
>>>> that into the GENERIC or GIMPLE match.pd path).
>>>
>>> Hi,
>>>
>>> I did some experimentation using ‘temporary GIMPLE with a SSA def (and then
>>> feed that into the GIMPLE match.pd path’.  Could we consider the code in the
>>> attachment(I did a test and the code took effect)?
>>
>> No, that's excessive overhead IMHO - the whole point of these functions
>> originally was to avoid build2 (...) on both conditionals.  If we
>> now create two SSA names and two GIMPLE statements that's too much.
>>
>> As said it shouldn't be rocket science to teach genmatch to
>> auto-generate those functions from match.pd patterns but it certainly
>> is some work (less so for somebody with genmatch knowledge).
>> I'll give it a poke...
> 
> OK, it's not so easy.  I guess we could lower the cost of building
> SSA names / gimple stmts significantly if we allocated them on the
> stack like via
> 
> gimple *stmt1 = XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN) + 2 *
> sizeof (tree));
> memset (stmt1, 0, ...);
> gimple_set_code (stmt1, GIMPLE_ASSIGN);
> gimple_set_num_ops (stmt1, 3);
> gimple_init_singleton (stmt1);
> 
> gimple_stmt_iterator gsi = gsi_for_stmt (stmt1);
> gimple_assign_set_rhs_with_ops (&gsi, actual operation...);
> 
> tree lhs1 = XALLOCA (tree_ssa_name);
> memset (lhs1, 0, sizeof (tree_ssa_name));
> TREE_SET_CODE (lhs1, SSA_NAME);
> TREE_TYPE (lhs1) = ...;
> 
> gimple_assing_set_lhs (stmt1, lhs1);
> 
> it's all a bit ugly and some factoring in the generic gimple machinery
> might easen this kind of hacks, but well...
> 
> With the above you could then use
> 
>    gimple_match_op op (gimple_match_cond::UNCOND, BIT_AND_EXPR /* or OR */,
> 		      boolean_type_node, lhs1, lhs2);
>    if (gimple_resimplify2 (NULL, &op, follow_all_ssa_edges))
>      ... successfully simplified into 'op' ...
> 
> with the simplification path then extracting the simplified result
> from 'op'.  Note this deliberately leaves out passing a gimple_seq
> as storage for more complex simplification results to match
> existing behavior.
> 
> Your patch has the GC allocation and SSA name (and namespace!)
> allocation overhead and most definitely misses releasing the
> SSA names you allocated.
> 
> Note with the above hack the simplified result has to be checked
> for mentions of lhs1 or lhs2 - a case we have to reject because
> their definitions are transitional.
> 

Hi,

   I made some changes based on the recommendations. Would you like to
   help me to see it again ? Sorry, it took so long time to provide the
   patch.

   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
	The reason is that I did not found a good way to handle the
	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
	Maybe I missing some important information about match.pd.
	2. The gimple_resimplify2 function is not used.  Since stmt1,
	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
	question with the value on the stack as the return value ?
	I may have misunderstood Richard's intention.

Thanks,
Lijia He

> Richard.
> 
>> Richard.
>>
>>> Thanks,
>>> Lijia He
>>>
>>>>
>>>> maybe_fold_and/or_comparisons handle two exploded binary expressions
>>>> while the current match.pd entries handle at most one exploded one
>>>> (the outermost then, either AND or OR).  But it would be definitely
>>>> doable to auto-generate maybe_fold_and/or_comparisons from match.pd
>>>> patterns which is what I'd ultimatively suggest to do (in some more
>>>> generalized form maybe).  Either with a separate genmatch invocation
>>>> or as part of the --gimple processing (not sure what is more feasible
>>>> here).
>>>>
>>>> I told Li Jia He that I don't expect him to do this work.
>>>>
>>>> Note I didn't review the actual patch yet.
>>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>
>>
>>
> 

[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/plain, Size: 7731 bytes --]

From 2699516000abdef60b06b203d703f80b8905cf09 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd

Hi,

This patch try to auto-generate maybe_fold_and/or_comparisons from match.pd.
We try to build tempory assign with SSA def and then feed that into the GIMPLE
match.pd path.

In order to lower the cost of building SSA names / gimple stmts significantly,
we need to allocated them on the stack.  This will cause the code a bit ugly.

The regression testing for the patch was done on GCC mainline on

	powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions.  Is it OK for trunk ?

Thanks,
Lijia He

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>

	* gimple.h (gimple_set_code): Declare.
	(gimple_size): Likewise.
	* gimple.c (gimple_set_code): Remove static and inline restrictions.
	(gimple_size): Likewise.
	* gimple-fold.c (maybe_fold_comparisons_from_match_pd): New function.
	(maybe_fold_and_comparisons): Modify and_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Modify or_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
---
 gcc/gimple-fold.c | 122 ++++++++++++++++++++++++++++++++++++++++++----
 gcc/gimple.c      |   4 +-
 gcc/gimple.h      |   2 +
 3 files changed, 117 insertions(+), 11 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index dfb31a02078..a5c2790361f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5789,6 +5789,91 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) (XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN)
+						  + 2 * sizeof (tree)));
+  memset (stmt1, 0, gimple_size (GIMPLE_ASSIGN) + 2 * sizeof (tree));
+  gimple_set_code (stmt1, GIMPLE_ASSIGN);
+  gimple_set_num_ops (stmt1, 3);
+  gimple_init_singleton (stmt1);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gimple *stmt2 = (gimple *) (XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN)
+						  + 2 * sizeof (tree)));
+  memset (stmt2, 0, gimple_size (GIMPLE_ASSIGN) + 2 * sizeof (tree));
+  gimple_set_code (stmt2, GIMPLE_ASSIGN);
+  gimple_set_num_ops (stmt2, 3);
+  gimple_init_singleton (stmt2);
+
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = XALLOCA (tree_node);
+  memset (lhs1, 0, sizeof (tree_node));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = boolean_type_node;
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = XALLOCA (tree_node);
+  memset (lhs2, 0, sizeof (tree_node));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = boolean_type_node;
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  /* Call the interface function of match.pd to simplify the expression.  */
+  tree t = gimple_simplify (code, boolean_type_node, gimple_assign_lhs (stmt1),
+			    gimple_assign_lhs (stmt2), NULL,
+			    follow_all_ssa_edges);
+
+  if (t)
+    {
+      switch (TREE_CODE (t))
+	{
+	  case SSA_NAME:
+	    {
+	      gimple *def = SSA_NAME_DEF_STMT (t);
+
+	      if (!is_gimple_assign (def)
+		  || TREE_CODE_CLASS (gimple_assign_rhs_code (def))
+		    != tcc_comparison)
+		return NULL_TREE;
+
+	      return fold_build2 (gimple_assign_rhs_code (def),
+				  boolean_type_node, gimple_assign_rhs1 (def),
+				  gimple_assign_rhs2 (def));
+	  }
+	case INTEGER_CST:
+	  /* Fold expression to boolean_true_node or boolean_false_node.  */
+	  return t;
+	default:
+	  return NULL_TREE;
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5800,11 +5885,21 @@ tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code2, op2a,
+						     op2b, code1, op1a, op1b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -6264,13 +6359,22 @@ tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code2, op2a,
+						     op2b, code1, op1a, op1b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 63c8d5e85ae..6769bd9edec 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -101,7 +101,7 @@ const enum gimple_code gcond::code_;
 
 /* Set the code for statement G to CODE.  */
 
-static inline void
+void
 gimple_set_code (gimple *g, enum gimple_code code)
 {
   g->code = code;
@@ -110,7 +110,7 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
+size_t
 gimple_size (enum gimple_code code)
 {
   return gsstruct_code_size[gss_for_code (code)];
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 47070e7f409..a32708ad349 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1447,6 +1447,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+void gimple_set_code (gimple *g, enum gimple_code code);
+size_t gimple_size (enum gimple_code code);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
-- 
2.17.1


[-- Attachment #3: 0002-Fix-PR88784-middle-end-is-missing-some-optimizations.patch --]
[-- Type: text/plain, Size: 19385 bytes --]

From 757bae5a8f3985f8704d846f1701bf345ab0fe43 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 03:50:34 -0500
Subject: [PATCH 2/2] Fix PR88784, middle end is missing some optimizations
 about unsigned

Hi,

According to the optimizable case described by Qi Feng on
issue 88784, we can combine the cases into the following:

1. x >  y  &&  x != XXX_MIN  -->   x > y
2. x >  y  &&  x == XXX_MIN  -->   false
3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN

4. x <  y  &&  x != XXX_MAX  -->   x < y
5. x <  y  &&  x == XXX_MAX  -->   false
6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX

7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
8. x <= y  ||  x != XXX_MIN  -->   true
9. x <= y  ||  x == XXX_MIN  -->   x <= y

10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
11. x >= y  ||  x != XXX_MAX  -->   true
12. x >= y  ||  x == XXX_MAX  -->   x >= y

Note: XXX_MIN represents the minimum value of type x.
      XXX_MAX represents the maximum value of type x.

Here we don't need to care about whether the operation is
signed or unsigned.  For example, in the below equation:

'x >  y  &&  x != XXX_MIN  -->   x > y'

If the x type is signed int and XXX_MIN is INT_MIN, we can
optimize it to 'x > y'.  However, if the type of x is unsigned
int and XXX_MIN is 0, we can still optimize it to 'x > y'.

The regression testing for the patch was done on GCC mainline on

    powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions.  Is it OK for trunk ?

Thanks,
Lijia He

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* match.pd (x >  y  &&  x != XXX_MIN): Optimize into 'x > y'.
	(x >  y  &&  x == XXX_MIN): Optimize into 'false'.
	(x <= y  &&  x == XXX_MIN): Optimize into 'x == XXX_MIN'.
	(x <  y  &&  x != XXX_MAX): Optimize into 'x < y'.
	(x <  y  &&  x == XXX_MAX): Optimize into 'false'.
	(x >= y  &&  x == XXX_MAX): Optimize into 'x == XXX_MAX'.
	(x >  y  ||  x != XXX_MIN): Optimize into 'x != XXX_MIN'.
	(x <= y  ||  x != XXX_MIN): Optimize into 'true'.
	(x <= y  ||  x == XXX_MIN): Optimize into 'x <= y'.
	(x <  y  ||  x != XXX_MAX): Optimize into 'x != XXX_MAX'.
	(x >= y  ||  x != XXX_MAX): Optimize into 'true'.
	(x >= y  ||  x == XXX_MAX): Optimize into 'x >= y'.

gcc/testsuite/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* gcc.dg/pr88784-1.c: New testcase.
	* gcc.dg/pr88784-2.c: New testcase.
	* gcc.dg/pr88784-3.c: New testcase.
	* gcc.dg/pr88784-4.c: New testcase.
	* gcc.dg/pr88784-5.c: New testcase.
	* gcc.dg/pr88784-6.c: New testcase.
	* gcc.dg/pr88784-7.c: New testcase.
	* gcc.dg/pr88784-8.c: New testcase.
	* gcc.dg/pr88784-9.c: New testcase.
	* gcc.dg/pr88784-10.c: New testcase.
	* gcc.dg/pr88784-11.c: New testcase.
	* gcc.dg/pr88784-12.c: New testcase.
---
 gcc/match.pd                      | 95 +++++++++++++++++++++++++++++++
 gcc/testsuite/gcc.dg/pr88784-1.c  | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-10.c | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-11.c | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-12.c | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-2.c  | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-3.c  | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-4.c  | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-5.c  | 31 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-6.c  | 31 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-7.c  | 31 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-8.c  | 31 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-9.c  | 32 +++++++++++
 13 files changed, 467 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-10.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-11.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-12.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-5.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-6.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-7.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-8.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-9.c

diff --git a/gcc/match.pd b/gcc/match.pd
index f8e35e96d22..21a147d0ff1 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1859,6 +1859,101 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     { wide_int_to_tree (type, (wi::to_wide (@1)
 			       & (bitpos / BITS_PER_UNIT))); }))))
 
+/* x >  y  &&  x != XXX_MIN  -->  x > y  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x >  y  &&  x == XXX_MIN  -->  false  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    { boolean_false_node; })))
+
+/* x <=  y  &&  x == XXX_MIN  -->  x == XXX_MIN  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (le:c @0 @1) (eq@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x <  y  &&  x != XXX_MAX  -->  x < y  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (lt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x <  y  &&  x == XXX_MAX  -->  false  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (lt:c @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    { boolean_false_node; })))
+
+/* x >=  y  &&  x == XXX_MAX  -->  x == XXX_MAX  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (ge:c @0 @1) (eq@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x >  y  ||  x != XXX_MIN   -->  x != XXX_MIN  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (gt:c @0 @1) (ne@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x <=  y  ||  x != XXX_MIN   -->  true  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    { boolean_true_node; })))
+
+/* x <=  y  ||  x == XXX_MIN   -->  x <= y  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c@3 @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x <  y  ||  x != XXX_MAX   -->  x != XXX_MAX  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (lt:c @0 @1) (ne@3 @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    @3)))
+
+/* x >=  y  ||  x != XXX_MAX   -->  true  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (ge:c @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    { boolean_true_node; })))
+
+/* x >=  y  ||  x == XXX_MAX   -->  x >= y  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (ge:c@3 @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P (TREE_TYPE(@1))
+       && wi::eq_p (wi::to_wide (@2), wi::max_value (TREE_TYPE (@2))))
+    @3)))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
diff --git a/gcc/testsuite/gcc.dg/pr88784-1.c b/gcc/testsuite/gcc.dg/pr88784-1.c
new file mode 100644
index 00000000000..067d40d0739
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-10.c b/gcc/testsuite/gcc.dg/pr88784-10.c
new file mode 100644
index 00000000000..2218faa3b7c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-10.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " <= " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " >= " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-11.c b/gcc/testsuite/gcc.dg/pr88784-11.c
new file mode 100644
index 00000000000..4465910efbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-11.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-12.c b/gcc/testsuite/gcc.dg/pr88784-12.c
new file mode 100644
index 00000000000..477bba07821
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-12.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-2.c b/gcc/testsuite/gcc.dg/pr88784-2.c
new file mode 100644
index 00000000000..02647204726
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-3.c b/gcc/testsuite/gcc.dg/pr88784-3.c
new file mode 100644
index 00000000000..be2ce315e60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-4.c b/gcc/testsuite/gcc.dg/pr88784-4.c
new file mode 100644
index 00000000000..d1363659f40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-4.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " > " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " < " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-5.c b/gcc/testsuite/gcc.dg/pr88784-5.c
new file mode 100644
index 00000000000..c6a349d7c75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-6.c b/gcc/testsuite/gcc.dg/pr88784-6.c
new file mode 100644
index 00000000000..b0e81e0165e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-6.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " >= " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-7.c b/gcc/testsuite/gcc.dg/pr88784-7.c
new file mode 100644
index 00000000000..937d2d26593
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-8.c b/gcc/testsuite/gcc.dg/pr88784-8.c
new file mode 100644
index 00000000000..aa384c305b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " < " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-9.c b/gcc/testsuite/gcc.dg/pr88784-9.c
new file mode 100644
index 00000000000..94f62d94ede
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-9.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
-- 
2.17.1


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-16  6:54               ` Li Jia He
@ 2019-08-30 11:16                 ` Martin Liška
  2019-09-05 13:01                 ` Richard Biener
  2019-09-05 13:17                 ` [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Richard Biener
  2 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-08-30 11:16 UTC (permalink / raw)
  To: Li Jia He, Richard Biener
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool, wschmidt

@Richi: PING^1

On 7/16/19 8:35 AM, Li Jia He wrote:
> 
> 
> On 2019/7/2 4:51 PM, Richard Biener wrote:
>> On Tue, 2 Jul 2019, Richard Biener wrote:
>>
>>> On Tue, 2 Jul 2019, Li Jia He wrote:
>>>
>>>>
>>>>
>>>> On 2019/7/1 3:30 PM, Richard Biener wrote:
>>>>> On Fri, 28 Jun 2019, Andrew Pinski wrote:
>>>>>
>>>>>> On Thu, Jun 27, 2019 at 9:55 PM Li Jia He <helijia@linux.ibm.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 2019/6/27 11:48 PM, Jeff Law wrote:
>>>>>>>> On 6/27/19 12:11 AM, Li Jia He wrote:
>>>>>>>>> Hi,
>>>>>>>>>
>>>>>>>>> According to the optimizable case described by Qi Feng on
>>>>>>>>> issue 88784, we can combine the cases into the following:
>>>>>>>>>
>>>>>>>>> 1. x >  y  &&  x != XXX_MIN  -->   x > y
>>>>>>>>> 2. x >  y  &&  x == XXX_MIN  -->   false
>>>>>>>>> 3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN
>>>>>>>>>
>>>>>>>>> 4. x <  y  &&  x != XXX_MAX  -->   x < y
>>>>>>>>> 5. x <  y  &&  x == XXX_MAX  -->   false
>>>>>>>>> 6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX
>>>>>>>>>
>>>>>>>>> 7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
>>>>>>>>> 8. x <= y  ||  x != XXX_MIN  -->   true
>>>>>>>>> 9. x <= y  ||  x == XXX_MIN  -->   x <= y
>>>>>>>>>
>>>>>>>>> 10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
>>>>>>>>> 11. x >= y  ||  x != XXX_MAX  -->   true
>>>>>>>>> 12. x >= y  ||  x == XXX_MAX  -->   x >= y
>>>>>>>>>
>>>>>>>>> Note: XXX_MIN represents the minimum value of type x.
>>>>>>>>>          XXX_MAX represents the maximum value of type x.
>>>>>>>>>
>>>>>>>>> Here we don't need to care about whether the operation is
>>>>>>>>> signed or unsigned.  For example, in the below equation:
>>>>>>>>>
>>>>>>>>> 'x >  y  &&  x != XXX_MIN  -->   x > y'
>>>>>>>>>
>>>>>>>>> If the x type is signed int and XXX_MIN is INT_MIN, we can
>>>>>>>>> optimize it to 'x > y'.  However, if the type of x is unsigned
>>>>>>>>> int and XXX_MIN is 0, we can still optimize it to 'x > y'.
>>>>>>>>>
>>>>>>>>> The regression testing for the patch was done on GCC mainline on
>>>>>>>>>
>>>>>>>>>        powerpc64le-unknown-linux-gnu (Power 9 LE)
>>>>>>>>>
>>>>>>>>> with no regressions.  Is it OK for trunk ?
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Lijia He
>>>>>>>>>
>>>>>>>>> gcc/ChangeLog
>>>>>>>>>
>>>>>>>>> 2019-06-27  Li Jia He  <helijia@linux.ibm.com>
>>>>>>>>>            Qi Feng  <ffengqi@linux.ibm.com>
>>>>>>>>>
>>>>>>>>>        PR middle-end/88784
>>>>>>>>>        * gimple-fold.c (and_comparisons_contain_equal_operands): New
>>>>>>>>> function.
>>>>>>>>>        (and_comparisons_1): Use
>>>>>>>>> and_comparisons_contain_equal_operands.
>>>>>>>>>        (or_comparisons_contain_equal_operands): New function.
>>>>>>>>>        (or_comparisons_1): Use or_comparisons_contain_equal_operands.
>>>>>>>> Would this be better done via match.pd?  ISTM this transformation
>>>>>>>> would
>>>>>>>> be well suited for that framework.
>>>>>>>
>>>>>>> Hi, Jeff
>>>>>>>
>>>>>>> I did this because of the following test case:
>>>>>>> `
>>>>>>> _Bool comp(unsigned x, unsigned y)
>>>>>>> {
>>>>>>>      return x > y && x != 0;
>>>>>>> }
>>>>>>> `
>>>>>>> The gimple file dumped on the power platform is:
>>>>>>> `
>>>>>>> comp (unsigned int x, unsigned int y)
>>>>>>> {
>>>>>>>      _Bool D.2837;
>>>>>>>      int iftmp.0;
>>>>>>>
>>>>>>>      if (x > y) goto <D.2841>; else goto <D.2839>;
>>>>>>>      <D.2841>:
>>>>>>>      if (x != 0) goto <D.2842>; else goto <D.2839>;
>>>>>>>      <D.2842>:
>>>>>>>      iftmp.0 = 1;
>>>>>>>      goto <D.2840>;
>>>>>>>      <D.2839>:
>>>>>>>      iftmp.0 = 0;
>>>>>>>      <D.2840>:
>>>>>>>      D.2837 = (_Bool) iftmp.0;
>>>>>>>      return D.2837;
>>>>>>> }
>>>>>>> `
>>>>>>> However, the gimple file dumped on x86 is
>>>>>>> `
>>>>>>> comp (unsigned int x, unsigned int y)
>>>>>>> {
>>>>>>>      _Bool D.2837;
>>>>>>>
>>>>>>>      _1 = x > y;
>>>>>>>      _2 = x != 0;
>>>>>>>      _3 = _1 & _2;
>>>>>>>      _4 = (int) _3;
>>>>>>>      D.2837 = (_Bool) _4;
>>>>>>>      return D.2837;
>>>>>>> }
>>>>>>> `
>>>>>>>
>>>>>>> The reason for the inconsistency between these two behaviors is param
>>>>>>> logical-op-non-short-circuit.  If we add the pattern to the match.pd
>>>>>>> file, we can only optimize the situation in which the statement is in
>>>>>>> the same basic block (logical-op-non-short-circuit=1, x86).  But for
>>>>>>> a cross-basic block (logical-op-non-short-circuit=0, power), match.pd
>>>>>>> can't handle this situation.
>>>>>>>
>>>>>>> Another reason is that I found out maybe_fold_and_comparisons and
>>>>>>> maybe_fold_or_comparisons are not only called by ifcombine pass but
>>>>>>> also by reassoc pass. Using this method can basically unify param
>>>>>>> logical-op-non-short-circuit=0 or 1.
>>>>>>
>>>>>>
>>>>>> As mentioned before ifcombine pass should be using gimple-match
>>>>>> instead of fold_build.  Try converting ifcombine over to gimple-match
>>>>>> infrastructure and add these to match.pd.
>>>>>
>>>>> Yes, I mentioned that in the PR.  The issue is that at the moment
>>>>> to combine x > y with x <= y you'd have to build GENERIC trees
>>>>> for both or temporary GIMPLE assign with a SSA def (and then feed
>>>>> that into the GENERIC or GIMPLE match.pd path).
>>>>
>>>> Hi,
>>>>
>>>> I did some experimentation using ‘temporary GIMPLE with a SSA def (and then
>>>> feed that into the GIMPLE match.pd path’.  Could we consider the code in the
>>>> attachment(I did a test and the code took effect)?
>>>
>>> No, that's excessive overhead IMHO - the whole point of these functions
>>> originally was to avoid build2 (...) on both conditionals.  If we
>>> now create two SSA names and two GIMPLE statements that's too much.
>>>
>>> As said it shouldn't be rocket science to teach genmatch to
>>> auto-generate those functions from match.pd patterns but it certainly
>>> is some work (less so for somebody with genmatch knowledge).
>>> I'll give it a poke...
>>
>> OK, it's not so easy.  I guess we could lower the cost of building
>> SSA names / gimple stmts significantly if we allocated them on the
>> stack like via
>>
>> gimple *stmt1 = XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN) + 2 *
>> sizeof (tree));
>> memset (stmt1, 0, ...);
>> gimple_set_code (stmt1, GIMPLE_ASSIGN);
>> gimple_set_num_ops (stmt1, 3);
>> gimple_init_singleton (stmt1);
>>
>> gimple_stmt_iterator gsi = gsi_for_stmt (stmt1);
>> gimple_assign_set_rhs_with_ops (&gsi, actual operation...);
>>
>> tree lhs1 = XALLOCA (tree_ssa_name);
>> memset (lhs1, 0, sizeof (tree_ssa_name));
>> TREE_SET_CODE (lhs1, SSA_NAME);
>> TREE_TYPE (lhs1) = ...;
>>
>> gimple_assing_set_lhs (stmt1, lhs1);
>>
>> it's all a bit ugly and some factoring in the generic gimple machinery
>> might easen this kind of hacks, but well...
>>
>> With the above you could then use
>>
>>    gimple_match_op op (gimple_match_cond::UNCOND, BIT_AND_EXPR /* or OR */,
>>               boolean_type_node, lhs1, lhs2);
>>    if (gimple_resimplify2 (NULL, &op, follow_all_ssa_edges))
>>      ... successfully simplified into 'op' ...
>>
>> with the simplification path then extracting the simplified result
>> from 'op'.  Note this deliberately leaves out passing a gimple_seq
>> as storage for more complex simplification results to match
>> existing behavior.
>>
>> Your patch has the GC allocation and SSA name (and namespace!)
>> allocation overhead and most definitely misses releasing the
>> SSA names you allocated.
>>
>> Note with the above hack the simplified result has to be checked
>> for mentions of lhs1 or lhs2 - a case we have to reject because
>> their definitions are transitional.
>>
> 
> Hi,
> 
>   I made some changes based on the recommendations. Would you like to
>   help me to see it again ? Sorry, it took so long time to provide the
>   patch.
> 
>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
>     The reason is that I did not found a good way to handle the
>     optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
>     Maybe I missing some important information about match.pd.
>     2. The gimple_resimplify2 function is not used.  Since stmt1,
>     stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
>     question with the value on the stack as the return value ?
>     I may have misunderstood Richard's intention.
> 
> Thanks,
> Lijia He
> 
>> Richard.
>>
>>> Richard.
>>>
>>>> Thanks,
>>>> Lijia He
>>>>
>>>>>
>>>>> maybe_fold_and/or_comparisons handle two exploded binary expressions
>>>>> while the current match.pd entries handle at most one exploded one
>>>>> (the outermost then, either AND or OR).  But it would be definitely
>>>>> doable to auto-generate maybe_fold_and/or_comparisons from match.pd
>>>>> patterns which is what I'd ultimatively suggest to do (in some more
>>>>> generalized form maybe).  Either with a separate genmatch invocation
>>>>> or as part of the --gimple processing (not sure what is more feasible
>>>>> here).
>>>>>
>>>>> I told Li Jia He that I don't expect him to do this work.
>>>>>
>>>>> Note I didn't review the actual patch yet.
>>>>>
>>>>> Thanks,
>>>>> Richard.
>>>>>
>>>>
>>>
>>>
>>

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-16  6:54               ` Li Jia He
  2019-08-30 11:16                 ` Martin Liška
@ 2019-09-05 13:01                 ` Richard Biener
  2019-09-05 18:47                   ` Martin Liška
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
  2019-09-05 13:17                 ` [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Richard Biener
  2 siblings, 2 replies; 56+ messages in thread
From: Richard Biener @ 2019-09-05 13:01 UTC (permalink / raw)
  To: Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

On Tue, 16 Jul 2019, Li Jia He wrote:

> Hi,
> 
>   I made some changes based on the recommendations. Would you like to
>   help me to see it again ? Sorry, it took so long time to provide the
>   patch.
> 
>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
> 	The reason is that I did not found a good way to handle the
> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
> 	Maybe I missing some important information about match.pd.
> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
> 	question with the value on the stack as the return value ?
> 	I may have misunderstood Richard's intention.

Sorry for the delay in reviewing.

Rather than exporting gimple_set_code and gimple_size I'd split
out a

void
gimple_init (gimple *, enum gimple_code code, unsigned nops);

from gimple_alloc (changing that to GC allocate not cleared
memory) doing all of the actual initialization.  Then the
allocation would go like

gimple *stmt1 = (gimple *)XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 
3));
gimple_init (stmt1, GIMPLE_ASSIGN, 3);

with an overload for gimple_size to account for # of ops.

+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = XALLOCA (tree_node);

you can use (tree) XALLOCA (tree_ssa_name) here

+  /* Call the interface function of match.pd to simplify the expression.  
*/
+  tree t = gimple_simplify (code, boolean_type_node, gimple_assign_lhs 
(stmt1),
+                           gimple_assign_lhs (stmt2), NULL,
+                           follow_all_ssa_edges);
+
+  if (t)

As I told Martin offline the appropriate function to use is

 You'd do

  gimple_match_op op (gimple_match_cond::UNCOND, code,
         boolean_type_node, gimple_assign_lhs (stmt1),
gimple_assign_lhs (stmt2));
  if (op->resimplify (NULL, follow_all_ssa_edges))
   {
      if (gimple_simplified_result_is_gimple_val (res_op))
        .. got a constant or SSA name ..
      else if (res_op->code.is_tree_code ()
                 && TREE_CODE_CLASS ((tree_code)res_op->code)) ==
tcc_comparison)
        ... got a comparison res_op->op[0] res_op->code res_op->op[1] ...

so you get the outermost expression back decomposed.

Otherwise with you passing NULL as the gimple_seq you'll miss quite
some simplification cases.

You also have to watch out for the result containing the LHS of one
of your temporary stmts.

+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, 
op1a,
+                                                    op1b, code2, op2a, 
op2b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code2, 
op2a,
+                                                    op2b, code1, op1a, 
op1b))
+    return t;

with match.pd rules you shouldn't need to call this twice, once with
swapped operands.

Otherwise this first patch looks like what I'd have done and we
can build upon it.

Not sure if you or Martin wants to improve it according to my
comments.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-07-16  6:54               ` Li Jia He
  2019-08-30 11:16                 ` Martin Liška
  2019-09-05 13:01                 ` Richard Biener
@ 2019-09-05 13:17                 ` Richard Biener
  2019-09-05 18:47                   ` Martin Liška
  2019-09-06 10:14                   ` [PATCH 2/2] Fix PR88784, middle " Martin Liška
  2 siblings, 2 replies; 56+ messages in thread
From: Richard Biener @ 2019-09-05 13:17 UTC (permalink / raw)
  To: Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

On Tue, 16 Jul 2019, Li Jia He wrote:

> Hi,
> 
>   I made some changes based on the recommendations. Would you like to
>   help me to see it again ? Sorry, it took so long time to provide the
>   patch.
> 
>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
> 	The reason is that I did not found a good way to handle the
> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
> 	Maybe I missing some important information about match.pd.
> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
> 	question with the value on the stack as the return value ?
> 	I may have misunderstood Richard's intention.

And now for the match.pd patch.

+/* x >  y  &&  x != XXX_MIN  -->  x > y  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
(TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    @3)))
+
+/* x >  y  &&  x == XXX_MIN  -->  false  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
(TREE_TYPE(@1))
+       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
+    { boolean_false_node; })))

you could merge those two via

 (for eqne (eq ne)
  (for and (....
   (simplify
    (and:c (gt:c @0 @1) (eqne @0 INTEGER_CST@2))
    (if (...)
     (switch
      (if (eqne == NE_EXPR)
       @3)
      (if (eqne == EQ_EXPR)
       { constant_boolean_node (false, type); }))))

notice using constant_boolean_node (false, type); instead of
boolean_false_node.  I suspect more unification is possible.

Also you could do

(match min_value
 INTEGER_CST
 (if (INTEGRAL_TYPE_P (type)
      && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))

and then write

 (simplify
  (and:c (gt:c @0 @1) (eq @0 min_value))
  (...

Your

(if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P
(TREE_TYPE(@1))

is redundant, it's enough to check either @0 or @1 given they
have to be compatible for the gt operation.  Note you probably
want to use

  (and:c (gt:c @0 @1) (eq @@0 min_value))

and verify that types_match (@1, @0) because when @0 are a constant
(and (eq @0 min_value) is not folded which can happen) then they
might have different types and thus you could have
(SHORT_MAX > intvar) && (SHORT_MAX == SHORT_MAX)

That said, the patterns can be quite a bit simplified I think.

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-09-05 13:01                 ` Richard Biener
@ 2019-09-05 18:47                   ` Martin Liška
  2019-09-06  8:01                     ` Richard Biener
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
  1 sibling, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-05 18:47 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

On 9/5/19 3:01 PM, Richard Biener wrote:
> Not sure if you or Martin wants to improve it according to my
> comments.

Yes please. I'm working on that based on the review you provided.

Thanks,
Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-09-05 13:17                 ` [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Richard Biener
@ 2019-09-05 18:47                   ` Martin Liška
  2019-09-06 10:14                   ` [PATCH 2/2] Fix PR88784, middle " Martin Liška
  1 sibling, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-05 18:47 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

On 9/5/19 3:17 PM, Richard Biener wrote:
> That said, the patterns can be quite a bit simplified I think.

I will take care of it as well.

Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-09-05 18:47                   ` Martin Liška
@ 2019-09-06  8:01                     ` Richard Biener
  2019-09-06  8:04                       ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-06  8:01 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 487 bytes --]

On Thu, 5 Sep 2019, Martin Liška wrote:

> On 9/5/19 3:01 PM, Richard Biener wrote:
> > Not sure if you or Martin wants to improve it according to my
> > comments.
> 
> Yes please. I'm working on that based on the review you provided.

Oh, and it just occured to me since we're doing single_use checks
on SSA names in match.pd that you need to initialize the
SSA_NAME_IMM_USE_NODE () as well - see make_ssa_name_fn, probably
makes sense to split out a short helper for that.

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned
  2019-09-06  8:01                     ` Richard Biener
@ 2019-09-06  8:04                       ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-06  8:04 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/6/19 10:01 AM, Richard Biener wrote:
> On Thu, 5 Sep 2019, Martin Liška wrote:
> 
>> On 9/5/19 3:01 PM, Richard Biener wrote:
>>> Not sure if you or Martin wants to improve it according to my
>>> comments.
>>
>> Yes please. I'm working on that based on the review you provided.
> 
> Oh, and it just occured to me since we're doing single_use checks
> on SSA names in match.pd that you need to initialize the
> SSA_NAME_IMM_USE_NODE () as well - see make_ssa_name_fn, probably
> makes sense to split out a short helper for that.

Yes, I already hit the ICE :)

Martin

> 
> Richard.
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-05 13:01                 ` Richard Biener
  2019-09-05 18:47                   ` Martin Liška
@ 2019-09-06 10:13                   ` Martin Liška
  2019-09-09 12:23                     ` Martin Liška
                                       ` (3 more replies)
  1 sibling, 4 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-06 10:13 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 3447 bytes --]

On 9/5/19 3:01 PM, Richard Biener wrote:
> On Tue, 16 Jul 2019, Li Jia He wrote:
> 
>> Hi,
>>
>>   I made some changes based on the recommendations. Would you like to
>>   help me to see it again ? Sorry, it took so long time to provide the
>>   patch.
>>
>>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
>> 	The reason is that I did not found a good way to handle the
>> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
>> 	Maybe I missing some important information about match.pd.
>> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
>> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
>> 	question with the value on the stack as the return value ?
>> 	I may have misunderstood Richard's intention.
> 
> Sorry for the delay in reviewing.
> 
> Rather than exporting gimple_set_code and gimple_size I'd split
> out a
> 
> void
> gimple_init (gimple *, enum gimple_code code, unsigned nops);
> 
> from gimple_alloc (changing that to GC allocate not cleared
> memory) doing all of the actual initialization.  Then the
> allocation would go like
> 
> gimple *stmt1 = (gimple *)XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 
> 3));
> gimple_init (stmt1, GIMPLE_ASSIGN, 3);
> 
> with an overload for gimple_size to account for # of ops.
> 
> +  /* Allocate SSA names(lhs1) on the stack.  */
> +  tree lhs1 = XALLOCA (tree_node);
> 
> you can use (tree) XALLOCA (tree_ssa_name) here
> 
> +  /* Call the interface function of match.pd to simplify the expression.  
> */
> +  tree t = gimple_simplify (code, boolean_type_node, gimple_assign_lhs 
> (stmt1),
> +                           gimple_assign_lhs (stmt2), NULL,
> +                           follow_all_ssa_edges);
> +
> +  if (t)
> 
> As I told Martin offline the appropriate function to use is
> 
>  You'd do
> 
>   gimple_match_op op (gimple_match_cond::UNCOND, code,
>          boolean_type_node, gimple_assign_lhs (stmt1),
> gimple_assign_lhs (stmt2));
>   if (op->resimplify (NULL, follow_all_ssa_edges))
>    {
>       if (gimple_simplified_result_is_gimple_val (res_op))
>         .. got a constant or SSA name ..
>       else if (res_op->code.is_tree_code ()
>                  && TREE_CODE_CLASS ((tree_code)res_op->code)) ==
> tcc_comparison)
>         ... got a comparison res_op->op[0] res_op->code res_op->op[1] ...
> 
> so you get the outermost expression back decomposed.
> 
> Otherwise with you passing NULL as the gimple_seq you'll miss quite
> some simplification cases.
> 
> You also have to watch out for the result containing the LHS of one
> of your temporary stmts.
> 
> +  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, 
> op1a,
> +                                                    op1b, code2, op2a, 
> op2b))
> +    return t;
> +
> +  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code2, 
> op2a,
> +                                                    op2b, code1, op1a, 
> op1b))
> +    return t;
> 
> with match.pd rules you shouldn't need to call this twice, once with
> swapped operands.
> 
> Otherwise this first patch looks like what I'd have done and we
> can build upon it.
> 
> Not sure if you or Martin wants to improve it according to my
> comments.
> 
> Thanks,
> Richard.
> 

I'm sending patch that addresses the feedback from Richard.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 10311 bytes --]

From 6f8feb5ccf46bae2c65b88a90661e23521ce9143 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple.h (gimple_init): Declare.
	(gimple_size): Likewise.
	* gimple.c (gimple_init): Remove static and inline restrictions.
	(gimple_alloc): Only allocate memory and call gimple_init.
	(gimple_size): Likewise.
	* gimple-fold.c (maybe_fold_comparisons_from_match_pd): New function.
	(maybe_fold_and_comparisons): Modify and_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Modify or_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	* tree-ssanames.c (init_ssa_name_imm_use): Use make_ssa_name_fn.
	(make_ssa_name_fn): New.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c   | 108 ++++++++++++++++++++++++++++++++++++++++----
 gcc/gimple.c        |  37 +++++++++------
 gcc/gimple.h        |   2 +
 gcc/tree-ssanames.c |  21 ++++++---
 gcc/tree-ssanames.h |   1 +
 5 files changed, 138 insertions(+), 31 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..5a42d5bebee 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5834,6 +5834,85 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gimple *stmt2 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = boolean_type_node;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = boolean_type_node;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      boolean_type_node, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  switch (TREE_CODE (res))
+	    {
+	    case SSA_NAME:
+		{
+		  gimple *def = SSA_NAME_DEF_STMT (res);
+
+		  if (!is_gimple_assign (def)
+		      || TREE_CODE_CLASS (gimple_assign_rhs_code (def))
+		      != tcc_comparison)
+		    return NULL_TREE;
+
+		  return fold_build2 (gimple_assign_rhs_code (def),
+				      boolean_type_node, gimple_assign_rhs1 (def),
+				      gimple_assign_rhs2 (def));
+		}
+	    case INTEGER_CST:
+	      /* Fold expression to boolean_true_node or boolean_false_node.  */
+	      return res;
+	    default:
+	      return NULL_TREE;
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5845,11 +5924,17 @@ tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -6309,13 +6394,18 @@ tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 2/2] Fix PR88784, middle end is missing some optimizations about unsigned
  2019-09-05 13:17                 ` [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Richard Biener
  2019-09-05 18:47                   ` Martin Liška
@ 2019-09-06 10:14                   ` Martin Liška
  2019-09-11 13:08                     ` Richard Biener
  1 sibling, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-06 10:14 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 2901 bytes --]

On 9/5/19 3:17 PM, Richard Biener wrote:
> On Tue, 16 Jul 2019, Li Jia He wrote:
> 
>> Hi,
>>
>>   I made some changes based on the recommendations. Would you like to
>>   help me to see it again ? Sorry, it took so long time to provide the
>>   patch.
>>
>>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
>> 	The reason is that I did not found a good way to handle the
>> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
>> 	Maybe I missing some important information about match.pd.
>> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
>> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
>> 	question with the value on the stack as the return value ?
>> 	I may have misunderstood Richard's intention.
> 
> And now for the match.pd patch.
> 
> +/* x >  y  &&  x != XXX_MIN  -->  x > y  */
> +(for and (truth_and bit_and)
> + (simplify
> +  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
> +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
> (TREE_TYPE(@1))
> +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
> +    @3)))
> +
> +/* x >  y  &&  x == XXX_MIN  -->  false  */
> +(for and (truth_and bit_and)
> + (simplify
> +  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
> +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
> (TREE_TYPE(@1))
> +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
> +    { boolean_false_node; })))
> 
> you could merge those two via
> 
>  (for eqne (eq ne)
>   (for and (....
>    (simplify
>     (and:c (gt:c @0 @1) (eqne @0 INTEGER_CST@2))
>     (if (...)
>      (switch
>       (if (eqne == NE_EXPR)
>        @3)
>       (if (eqne == EQ_EXPR)
>        { constant_boolean_node (false, type); }))))
> 
> notice using constant_boolean_node (false, type); instead of
> boolean_false_node.  I suspect more unification is possible.
> 
> Also you could do
> 
> (match min_value
>  INTEGER_CST
>  (if (INTEGRAL_TYPE_P (type)
>       && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
> 
> and then write
> 
>  (simplify
>   (and:c (gt:c @0 @1) (eq @0 min_value))
>   (...
> 
> Your
> 
> (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P
> (TREE_TYPE(@1))
> 
> is redundant, it's enough to check either @0 or @1 given they
> have to be compatible for the gt operation.  Note you probably
> want to use
> 
>   (and:c (gt:c @0 @1) (eq @@0 min_value))
> 
> and verify that types_match (@1, @0) because when @0 are a constant
> (and (eq @0 min_value) is not folded which can happen) then they
> might have different types and thus you could have
> (SHORT_MAX > intvar) && (SHORT_MAX == SHORT_MAX)
> 
> That said, the patterns can be quite a bit simplified I think.
> 
> Richard.
> 

Likewise, I applied the suggested simplification.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0002-Fix-PR88784-middle-end-is-missing-some-optimizations.patch --]
[-- Type: text/x-patch, Size: 19009 bytes --]

From 1006e2cf69e97692e09e845eaadf55098d48f0e2 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 03:50:34 -0500
Subject: [PATCH 2/2] Fix PR88784, middle end is missing some optimizations
 about unsigned

Hi,

According to the optimizable case described by Qi Feng on
issue 88784, we can combine the cases into the following:

1. x >  y  &&  x != XXX_MIN  -->   x > y
2. x >  y  &&  x == XXX_MIN  -->   false
3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN

4. x <  y  &&  x != XXX_MAX  -->   x < y
5. x <  y  &&  x == XXX_MAX  -->   false
6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX

7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
8. x <= y  ||  x != XXX_MIN  -->   true
9. x <= y  ||  x == XXX_MIN  -->   x <= y

10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
11. x >= y  ||  x != XXX_MAX  -->   true
12. x >= y  ||  x == XXX_MAX  -->   x >= y

Note: XXX_MIN represents the minimum value of type x.
      XXX_MAX represents the maximum value of type x.

Here we don't need to care about whether the operation is
signed or unsigned.  For example, in the below equation:

'x >  y  &&  x != XXX_MIN  -->   x > y'

If the x type is signed int and XXX_MIN is INT_MIN, we can
optimize it to 'x > y'.  However, if the type of x is unsigned
int and XXX_MIN is 0, we can still optimize it to 'x > y'.

The regression testing for the patch was done on GCC mainline on

    powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions.  Is it OK for trunk ?

Thanks,
Lijia He

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* match.pd (x >  y  &&  x != XXX_MIN): Optimize into 'x > y'.
	(x >  y  &&  x == XXX_MIN): Optimize into 'false'.
	(x <= y  &&  x == XXX_MIN): Optimize into 'x == XXX_MIN'.
	(x <  y  &&  x != XXX_MAX): Optimize into 'x < y'.
	(x <  y  &&  x == XXX_MAX): Optimize into 'false'.
	(x >= y  &&  x == XXX_MAX): Optimize into 'x == XXX_MAX'.
	(x >  y  ||  x != XXX_MIN): Optimize into 'x != XXX_MIN'.
	(x <= y  ||  x != XXX_MIN): Optimize into 'true'.
	(x <= y  ||  x == XXX_MIN): Optimize into 'x <= y'.
	(x <  y  ||  x != XXX_MAX): Optimize into 'x != XXX_MAX'.
	(x >= y  ||  x != XXX_MAX): Optimize into 'true'.
	(x >= y  ||  x == XXX_MAX): Optimize into 'x >= y'.

gcc/testsuite/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* gcc.dg/pr88784-1.c: New testcase.
	* gcc.dg/pr88784-2.c: New testcase.
	* gcc.dg/pr88784-3.c: New testcase.
	* gcc.dg/pr88784-4.c: New testcase.
	* gcc.dg/pr88784-5.c: New testcase.
	* gcc.dg/pr88784-6.c: New testcase.
	* gcc.dg/pr88784-7.c: New testcase.
	* gcc.dg/pr88784-8.c: New testcase.
	* gcc.dg/pr88784-9.c: New testcase.
	* gcc.dg/pr88784-10.c: New testcase.
	* gcc.dg/pr88784-11.c: New testcase.
	* gcc.dg/pr88784-12.c: New testcase.
---
 gcc/match.pd                      | 91 +++++++++++++++++++++++++++++--
 gcc/testsuite/gcc.dg/pr88784-1.c  | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-10.c | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-11.c | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-12.c | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-2.c  | 30 ++++++++++
 gcc/testsuite/gcc.dg/pr88784-3.c  | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-4.c  | 32 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-5.c  | 31 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-6.c  | 31 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-7.c  | 31 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-8.c  | 31 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-9.c  | 32 +++++++++++
 13 files changed, 459 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-10.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-11.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-12.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-5.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-6.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-7.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-8.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-9.c

diff --git a/gcc/match.pd b/gcc/match.pd
index cd75dacd9cd..aa65cb63ca2 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1860,6 +1860,89 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     { wide_int_to_tree (type, (wi::to_wide (@1)
 			       & (bitpos / BITS_PER_UNIT))); }))))
 
+(match min_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
+
+(match max_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::max_value (type)))))
+
+/* x >  y  &&  x != XXX_MIN  -->  x > y
+   x >  y  &&  x == XXX_MIN  -->  false . */
+(for eqne (eq ne)
+ (for and (truth_and bit_and)
+  (simplify
+   (and:c (gt:c@2 @0 @1) (eqne @0 min_value))
+    (switch
+     (if (eqne == EQ_EXPR)
+      { constant_boolean_node (false, type); })
+     (if (eqne == NE_EXPR)
+      @2)
+     ))))
+
+/* x <  y  &&  x != XXX_MAX  -->  x < y
+   x <  y  &&  x == XXX_MAX  -->  false.  */
+(for eqne (eq ne)
+ (for and (truth_and bit_and)
+  (simplify
+   (and:c (lt:c@2 @0 @1) (eqne @0 max_value))
+    (switch
+     (if (eqne == EQ_EXPR)
+      { constant_boolean_node (false, type); })
+     (if (eqne == NE_EXPR)
+      @2)
+     ))))
+
+/* x <=  y  &&  x == XXX_MIN  -->  x == XXX_MIN.  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (le:c @0 @1) (eq@2 @0 min_value))
+   @2))
+
+/* x >=  y  &&  x == XXX_MAX  -->  x == XXX_MAX.  */
+(for and (truth_and bit_and)
+ (simplify
+  (and:c (ge:c @0 @1) (eq@2 @0 max_value))
+   @2))
+
+/* x >  y  ||  x != XXX_MIN   -->  x != XXX_MIN.  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (gt:c @0 @1) (ne@2 @0 min_value))
+   @2))
+
+/* x <=  y  ||  x != XXX_MIN   -->  true.  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c @0 @1) (ne @0 min_value))
+   { constant_boolean_node (true, type); }))
+
+/* x <=  y  ||  x == XXX_MIN   -->  x <= y.  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (le:c@2 @0 @1) (eq @0 min_value))
+   @2))
+
+/* x <  y  ||  x != XXX_MAX   -->  x != XXX_MAX.  */
+(for or (truth_or bit_ior)
+ (simplify
+  (or:c (lt:c @0 @1) (ne@2 @0 max_value))
+   @2))
+
+/* x >=  y  ||  x != XXX_MAX   -->  true
+   x >=  y  ||  x == XXX_MAX   -->  x >= y.  */
+(for eqne (eq ne)
+ (for or (truth_or bit_ior)
+  (simplify
+   (or:c (ge:c@2 @0 @1) (eqne @0 max_value))
+    (switch
+     (if (eqne == EQ_EXPR)
+      @2)
+     (if (eqne == NE_EXPR)
+      { constant_boolean_node (true, type); })))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
@@ -5402,10 +5485,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    on c, so could drop potentially-trapping arithmetic, but that's a valid
    simplification if the result of the operation isn't needed.
 
-   Avoid speculatively generating a stand-alone vector comparison                                                                                
-   on targets that might not support them.  Any target implementing                                                                              
-   conditional internal functions must support the same comparisons                                                                              
-   inside and outside a VEC_COND_EXPR.  */                                                                                                       
+   Avoid speculatively generating a stand-alone vector comparison
+   on targets that might not support them.  Any target implementing
+   conditional internal functions must support the same comparisons
+   inside and outside a VEC_COND_EXPR.  */
 
 #if GIMPLE
 (for uncond_op (UNCOND_BINARY)
diff --git a/gcc/testsuite/gcc.dg/pr88784-1.c b/gcc/testsuite/gcc.dg/pr88784-1.c
new file mode 100644
index 00000000000..067d40d0739
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-10.c b/gcc/testsuite/gcc.dg/pr88784-10.c
new file mode 100644
index 00000000000..2218faa3b7c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-10.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " <= " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " >= " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-11.c b/gcc/testsuite/gcc.dg/pr88784-11.c
new file mode 100644
index 00000000000..4465910efbb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-11.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-12.c b/gcc/testsuite/gcc.dg/pr88784-12.c
new file mode 100644
index 00000000000..477bba07821
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-12.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3 --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-2.c b/gcc/testsuite/gcc.dg/pr88784-2.c
new file mode 100644
index 00000000000..02647204726
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-3.c b/gcc/testsuite/gcc.dg/pr88784-3.c
new file mode 100644
index 00000000000..be2ce315e60
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-4.c b/gcc/testsuite/gcc.dg/pr88784-4.c
new file mode 100644
index 00000000000..d1363659f40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-4.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " > " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " < " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-5.c b/gcc/testsuite/gcc.dg/pr88784-5.c
new file mode 100644
index 00000000000..c6a349d7c75
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-6.c b/gcc/testsuite/gcc.dg/pr88784-6.c
new file mode 100644
index 00000000000..b0e81e0165e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-6.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " >= " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-7.c b/gcc/testsuite/gcc.dg/pr88784-7.c
new file mode 100644
index 00000000000..937d2d26593
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-8.c b/gcc/testsuite/gcc.dg/pr88784-8.c
new file mode 100644
index 00000000000..aa384c305b1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-gimple --param logical-op-non-short-circuit=1" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "gimple" } } */
+/* { dg-final { scan-tree-dump-not " < " "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-9.c b/gcc/testsuite/gcc.dg/pr88784-9.c
new file mode 100644
index 00000000000..94f62d94ede
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-9.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine --param logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
@ 2019-09-09 12:23                     ` Martin Liška
  2019-09-09 13:10                       ` Marc Glisse
  2019-09-09 13:10                       ` Richard Biener
  2019-09-09 12:24                     ` [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd Martin Liška
                                       ` (2 subsequent siblings)
  3 siblings, 2 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-09 12:23 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 364 bytes --]

Hi.

I'm sending slightly updated version of the patch where we
need to properly select type in maybe_fold_comparisons_from_match_pd
function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
and so that we can't return a boolean_type_node.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 10365 bytes --]

From b6165b1d4be04f47bfa2b511974f5b8e784acb41 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/5] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple.h (gimple_init): Declare.
	(gimple_size): Likewise.
	* gimple.c (gimple_init): Remove static and inline restrictions.
	(gimple_alloc): Only allocate memory and call gimple_init.
	(gimple_size): Likewise.
	* gimple-fold.c (maybe_fold_comparisons_from_match_pd): New function.
	(maybe_fold_and_comparisons): Modify and_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Modify or_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	* tree-ssanames.c (init_ssa_name_imm_use): Use make_ssa_name_fn.
	(make_ssa_name_fn): New.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c   | 112 ++++++++++++++++++++++++++++++++++++++++----
 gcc/gimple.c        |  37 +++++++++------
 gcc/gimple.h        |   2 +
 gcc/tree-ssanames.c |  21 ++++++---
 gcc/tree-ssanames.h |   1 +
 5 files changed, 142 insertions(+), 31 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..8a9eca13b87 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5834,6 +5834,89 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  tree type = TREE_TYPE (op1a);
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    type = boolean_type_node;
+
+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gimple *stmt2 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = type;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = type;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      type, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  switch (TREE_CODE (res))
+	    {
+	    case SSA_NAME:
+		{
+		  gimple *def = SSA_NAME_DEF_STMT (res);
+
+		  if (!is_gimple_assign (def)
+		      || TREE_CODE_CLASS (gimple_assign_rhs_code (def))
+		      != tcc_comparison)
+		    return NULL_TREE;
+
+		  return fold_build2 (gimple_assign_rhs_code (def),
+				      type, gimple_assign_rhs1 (def),
+				      gimple_assign_rhs2 (def));
+		}
+	    case INTEGER_CST:
+	      /* Fold expression to boolean_true_node or boolean_false_node.  */
+	      return res;
+	    default:
+	      return NULL_TREE;
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5845,11 +5928,17 @@ tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -6309,13 +6398,18 @@ tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
  2019-09-09 12:23                     ` Martin Liška
  2019-09-09 12:24                     ` [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd Martin Liška
@ 2019-09-09 12:24                     ` Martin Liška
  2019-09-09 13:41                       ` Martin Liška
  2019-09-09 12:25                     ` [PATCH 5/5] Rewrite second part of or_comparisons_1 " Martin Liška
  3 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 12:24 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 191 bytes --]

Hi.

The patch is about transition of and_comparisons_1 matching
into match.pd.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0003-Rewrite-part-of-and_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 25552 bytes --]

From 15045058d6caf84734ea949a297b6e31d9a8647c Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* genmatch.c (dt_node::append_simplify): Ignore warning
	for the same location.
	* gimple-fold.c (same_bool_result_p): Handle newly
	created SSA_NAMEs ar arguments.
	(and_comparisons_1): Add new argument gimple_stmt_iterator.
	(and_var_with_comparison): Likewise.
	(and_var_with_comparison_1): Likewise.
	(or_comparisons_1): Likewise.
	(or_var_with_comparison): Likewise.
	(or_var_with_comparison_1): Likewise.
	(maybe_fold_comparisons_from_match_pd): Handle creation
	of temporary SSA_NAMEs. Add new argument gimple_stmt_iterator.
	(maybe_fold_and_comparisons): Likewise.
	(maybe_fold_or_comparisons): Likewise.
	* gimple-fold.h (maybe_fold_and_comparisons): Likewise.
	(maybe_fold_or_comparisons): Likewise.
	* match.pd: Add rules for (X OP1 CST1) && (X OP2 CST2).
	* tree-if-conv.c (fold_or_predicates): Do not
	pass gimple_stmt_iterator.
	* tree-ssa-ifcombine.c (ifcombine_ifandif): Pass gimple_stmt_iterator.
	* tree-ssa-reassoc.c (eliminate_redundant_comparison): Do not
	pass gimple_stmt_iterator.
	(optimize_vec_cond_expr): Likewise.
---
 gcc/genmatch.c           |   4 +-
 gcc/gimple-fold.c        | 261 +++++++++++++--------------------------
 gcc/gimple-fold.h        |   6 +-
 gcc/match.pd             |  68 ++++++++++
 gcc/tree-if-conv.c       |   2 +-
 gcc/tree-ssa-ifcombine.c |   5 +-
 gcc/tree-ssa-reassoc.c   |  11 +-
 7 files changed, 172 insertions(+), 185 deletions(-)

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..b7194448a0f 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
 			  dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+	&& s->match->location != s2->s->match->location)
       {
 	warning_at (s->match->location, "duplicate pattern");
 	warning_at (s2->s->match->location, "previous pattern defined here");
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 8a9eca13b87..f9971c004b7 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5350,6 +5350,19 @@ same_bool_result_p (const_tree op1, const_tree op2)
   if (operand_equal_p (op1, op2, 0))
     return true;
 
+  /* Function maybe_fold_comparisons_from_match_pd creates temporary
+     SSA_NAMEs.  */
+  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+    {
+      gimple *s = SSA_NAME_DEF_STMT (op2);
+      if (is_gimple_assign (s))
+	return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+				       gimple_assign_rhs1 (s),
+				       gimple_assign_rhs2 (s));
+      else
+	return false;
+    }
+
   /* Check the cases where at least one of the operands is a comparison.
      These are a bit smarter than operand_equal_p in that they apply some
      identifies on SSA_NAMEs.  */
@@ -5372,22 +5385,28 @@ same_bool_result_p (const_tree op1, const_tree op2)
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b);
+		   enum tree_code code2, tree op2a, tree op2b,
+		   gimple_stmt_iterator *gsi);
 static tree
 and_var_with_comparison (tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b);
+			 enum tree_code code2, tree op2a, tree op2b,
+			 gimple_stmt_iterator *gsi);
 static tree
 and_var_with_comparison_1 (gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b);
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi);
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b);
+		  enum tree_code code2, tree op2a, tree op2b,
+		  gimple_stmt_iterator *gsi);
 static tree
 or_var_with_comparison (tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b);
+			enum tree_code code2, tree op2a, tree op2b,
+			gimple_stmt_iterator *gsi);
 static tree
 or_var_with_comparison_1 (gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b);
+			  enum tree_code code2, tree op2a, tree op2b,
+			  gimple_stmt_iterator *gsi);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
    ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
@@ -5396,7 +5415,8 @@ or_var_with_comparison_1 (gimple *stmt,
 
 static tree
 and_var_with_comparison (tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b)
+			 enum tree_code code2, tree op2a, tree op2b,
+			 gimple_stmt_iterator *gsi)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5411,9 +5431,9 @@ and_var_with_comparison (tree var, bool invert,
   if (invert)
     t = or_var_with_comparison_1 (stmt, 
 				  invert_tree_comparison (code2, false),
-				  op2a, op2b);
+				  op2a, op2b, gsi);
   else
-    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b, gsi);
   return canonicalize_bool (t, invert);
 }
 
@@ -5423,7 +5443,8 @@ and_var_with_comparison (tree var, bool invert,
 
 static tree
 and_var_with_comparison_1 (gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -5456,9 +5477,7 @@ and_var_with_comparison_1 (gimple *stmt,
       tree t = and_comparisons_1 (innercode,
 				  gimple_assign_rhs1 (stmt),
 				  gimple_assign_rhs2 (stmt),
-				  code2,
-				  op2a,
-				  op2b);
+				  code2, op2a, op2b, gsi);
       if (t)
 	return t;
     }
@@ -5489,11 +5508,13 @@ and_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: and_var_with_comparison (inner2, false, code2, op2a, op2b,
+					   gsi));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: and_var_with_comparison (inner1, false, code2, op2a, op2b,
+					   gsi));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
@@ -5503,7 +5524,7 @@ and_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -5535,7 +5556,7 @@ and_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -5589,7 +5610,8 @@ and_var_with_comparison_1 (gimple *stmt,
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b)
+		   enum tree_code code2, tree op2a, tree op2b,
+		   gimple_stmt_iterator *gsi)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -5618,136 +5640,6 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* If we have (op1a == op1b), we should either be able to
-	 return that or FALSE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-      /* Likewise if the second comparison is an == comparison.  */
-      else if (code2 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-
-      /* Same business with inequality tests.  */
-      else if (code1 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp != 0); break;
-	    case NE_EXPR: val = (cmp == 0); break;
-	    case LT_EXPR: val = (cmp >= 0); break;
-	    case GT_EXPR: val = (cmp <= 0); break;
-	    case LE_EXPR: val = (cmp > 0); break;
-	    case GE_EXPR: val = (cmp < 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp <= 0); break;
-	    case GT_EXPR: val = (cmp >= 0); break;
-	    case LE_EXPR: val = (cmp < 0); break;
-	    case GE_EXPR: val = (cmp > 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Chose the more restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Likewise chose the more restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
-		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
-	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for disjoint ranges. */
-      else if (cmp <= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_false_node;
-      else if (cmp >= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_false_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
@@ -5762,7 +5654,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b, gsi);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -5813,7 +5705,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = and_var_with_comparison (arg, invert, code2,
-						      op2a, op2b);
+						      op2a, op2b, gsi);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -5845,7 +5737,7 @@ static tree
 maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 				      tree op1a, tree op1b,
 				      enum tree_code code2, tree op2a,
-				      tree op2b)
+				      tree op2b, gimple_stmt_iterator *gsi)
 {
   tree type = TREE_TYPE (op1a);
   if (TREE_CODE (type) != VECTOR_TYPE)
@@ -5912,6 +5804,18 @@ maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 	      return NULL_TREE;
 	    }
 	}
+      else if (op.code.is_tree_code ()
+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+	{
+	  if (gsi)
+	    {
+	      tree r = make_ssa_name (type);
+	      gassign *assign = gimple_build_assign (r, (tree_code)op.code,
+						     op.ops[0], op.ops[1]);
+	      gsi_insert_before (gsi, assign, GSI_SAME_STMT);
+	      return r;
+	    }
+	}
     }
 
   return NULL_TREE;
@@ -5926,16 +5830,18 @@ maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 
 tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
-			    enum tree_code code2, tree op2a, tree op2b)
+			    enum tree_code code2, tree op2a, tree op2b,
+			    gimple_stmt_iterator *gsi)
 {
-  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b,
+						     gsi))
     return t;
 
-  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, gsi))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
-						     op1b, code2, op2a, op2b))
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, gsi))
     return t;
 
   return NULL_TREE;
@@ -5948,7 +5854,8 @@ maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 
 static tree
 or_var_with_comparison (tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b)
+			enum tree_code code2, tree op2a, tree op2b,
+			gimple_stmt_iterator *gsi)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5963,9 +5870,9 @@ or_var_with_comparison (tree var, bool invert,
   if (invert)
     t = and_var_with_comparison_1 (stmt, 
 				   invert_tree_comparison (code2, false),
-				   op2a, op2b);
+				   op2a, op2b, gsi);
   else
-    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b, gsi);
   return canonicalize_bool (t, invert);
 }
 
@@ -5975,7 +5882,8 @@ or_var_with_comparison (tree var, bool invert,
 
 static tree
 or_var_with_comparison_1 (gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b)
+			  enum tree_code code2, tree op2a, tree op2b,
+			  gimple_stmt_iterator *gsi)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -6008,9 +5916,7 @@ or_var_with_comparison_1 (gimple *stmt,
       tree t = or_comparisons_1 (innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
-				 code2,
-				 op2a,
-				 op2b);
+				 code2, op2a, op2b, gsi);
       if (t)
 	return t;
     }
@@ -6041,11 +5947,13 @@ or_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: or_var_with_comparison (inner2, false, code2, op2a, op2b,
+					  gsi));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: or_var_with_comparison (inner1, false, code2, op2a, op2b,
+					  gsi));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
@@ -6055,7 +5963,7 @@ or_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -6087,7 +5995,7 @@ or_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -6142,7 +6050,8 @@ or_var_with_comparison_1 (gimple *stmt,
 
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b)
+		  enum tree_code code2, tree op2a, tree op2b,
+		  gimple_stmt_iterator *gsi)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -6315,7 +6224,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b, gsi);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6366,7 +6275,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = or_var_with_comparison (arg, invert, code2,
-						     op2a, op2b);
+						     op2a, op2b, gsi);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -6396,16 +6305,18 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 
 tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi)
 {
-  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b,
+						     gsi))
     return t;
 
-  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, gsi))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
-						     op1b, code2, op2a, op2b))
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, gsi))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 673d484ff52..3c2d19862a0 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -32,9 +32,11 @@ extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
 extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, 
-					enum tree_code, tree, tree);
+					enum tree_code, tree, tree,
+					gimple_stmt_iterator *gsi);
 extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
-				       enum tree_code, tree, tree);
+				       enum tree_code, tree, tree,
+				       gimple_stmt_iterator *gsi);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
 extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
 extern bool arith_overflowed_p (enum tree_code, const_tree, const_tree,
diff --git a/gcc/match.pd b/gcc/match.pd
index 28512d19b73..2c64c460fda 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1949,6 +1949,74 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (if (eqne == NE_EXPR)
       { constant_boolean_node (true, type); })))))
 
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for and (truth_and bit_and)
+   (simplify
+    (and:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) (code1 @0 @1))
+       (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+       (if (code1 == NE_EXPR && !val) (code2 @0 @2))))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for and (truth_and bit_and)
+   (simplify
+   (and (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Chose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LE_EXPR && code2 == GE_EXPR)
+	       || (code1 == GE_EXPR && code2 == LE_EXPR)))
+       (eq @0 @1))
+      /* Check for disjoint ranges.  */
+      (if (cmp <= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (false, type); })
+      (if (cmp >= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (false, type); })
+      ))))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index da67e39e03a..459cba2f752 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -437,7 +437,7 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
       tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
-					  code2, op2a, op2b);
+					  code2, op2a, op2b, NULL);
       if (t)
 	return t;
     }
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index f30816ace7b..92542817604 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -555,15 +555,16 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 	return false;
       /* Don't return false so fast, try maybe_fold_or_comparisons?  */
 
+      gimple_stmt_iterator gsi = gsi_for_stmt (inner_cond);
       if (!(t = maybe_fold_and_comparisons (inner_cond_code,
 					    gimple_cond_lhs (inner_cond),
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
 					    gimple_cond_lhs (outer_cond),
-					    gimple_cond_rhs (outer_cond))))
+					    gimple_cond_rhs (outer_cond),
+					    &gsi)))
 	{
 	  tree t1, t2;
-	  gimple_stmt_iterator gsi;
 	  bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT;
 	  if (PARAM_VALUE (PARAM_LOGICAL_OP_NON_SHORT_CIRCUIT) != -1)
 	    logical_op_non_short_circuit
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index df76e66bccf..ae0752bb371 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -2091,11 +2091,13 @@ eliminate_redundant_comparison (enum tree_code opcode,
       if (opcode == BIT_IOR_EXPR)
 	t = maybe_fold_or_comparisons (lcode, op1, op2,
 				       rcode, gimple_assign_rhs1 (def2),
-				       gimple_assign_rhs2 (def2));
+				       gimple_assign_rhs2 (def2),
+				       NULL);
       else
 	t = maybe_fold_and_comparisons (lcode, op1, op2,
 					rcode, gimple_assign_rhs1 (def2),
-					gimple_assign_rhs2 (def2));
+					gimple_assign_rhs2 (def2),
+					NULL);
       if (!t)
 	continue;
 
@@ -3834,9 +3836,10 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 
 	  tree comb;
 	  if (opcode == BIT_AND_EXPR)
-	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1,
+					       NULL);
 	  else if (opcode == BIT_IOR_EXPR)
-	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1, NULL);
 	  else
 	    gcc_unreachable ();
 	  if (comb == NULL)
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
  2019-09-09 12:23                     ` Martin Liška
@ 2019-09-09 12:24                     ` Martin Liška
  2019-09-11 11:19                       ` Martin Liška
  2019-09-09 12:24                     ` [PATCH 3/5] Rewrite part of and_comparisons_1 " Martin Liška
  2019-09-09 12:25                     ` [PATCH 5/5] Rewrite second part of or_comparisons_1 " Martin Liška
  3 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 12:24 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 188 bytes --]

Hi.

Next part if about transition of part of the OR patterns
into match.pd.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0004-Rewrite-first-part-of-or_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 4748 bytes --]

From 0cc83b72025d243e9e6ebaa9a85c68c17f9cd09a Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:47:01 +0200
Subject: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules
	moved to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 87 +----------------------------------------------
 gcc/match.pd      | 29 ++++++++++++++++
 2 files changed, 30 insertions(+), 86 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index f9971c004b7..e691780591c 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6088,93 +6088,8 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
     {
       int cmp = tree_int_cst_compare (op1b, op2b);
 
-      /* If we have (op1a != op1b), we should either be able to
-	 return that or TRUE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	    }
-	}
-      /* Likewise if the second comparison is a != comparison.  */
-      else if (code2 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	    }
-	}
-
-      /* See if an equality test is redundant with the other comparison.  */
-      else if (code1 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
       /* Chose the less restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
+      if ((code1 == LT_EXPR || code1 == LE_EXPR)
 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
 	{
 	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
diff --git a/gcc/match.pd b/gcc/match.pd
index 2c64c460fda..2923f5b4cbe 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2017,6 +2017,35 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        { constant_boolean_node (false, type); })
       ))))))
 
+/* Convert (X == CST1) || (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for or (truth_or bit_ior)
+   (simplify
+    (or:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) (code2 @0 @2))
+       (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
+       (if (code1 == NE_EXPR && !val) (code1 @0 @1))))))))
+
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.
  2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
                                       ` (2 preceding siblings ...)
  2019-09-09 12:24                     ` [PATCH 3/5] Rewrite part of and_comparisons_1 " Martin Liška
@ 2019-09-09 12:25                     ` Martin Liška
  2019-09-11 11:19                       ` Martin Liška
  3 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 12:25 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 155 bytes --]

And finally the second part of OR patterns.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0005-Rewrite-second-part-of-or_comparisons_1-into-match.p.patch --]
[-- Type: text/x-patch, Size: 4517 bytes --]

From 621d25811179bce8a8ad58a88b742528e97917d6 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:59:36 +0200
Subject: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules moved
	to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 45 ---------------------------------------------
 gcc/match.pd      | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 45 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index e691780591c..ac24f3b408b 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6080,51 +6080,6 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* Chose the less restrictive of two < or <= comparisons.  */
-      if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Likewise chose the less restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LT_EXPR && code2 == GT_EXPR)
-		   || (code1 == GT_EXPR && code2 == LT_EXPR)))
-	return fold_build2 (NE_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for less/greater pairs that don't restrict the range at all.  */
-      else if (cmp >= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_true_node;
-      else if (cmp <= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_true_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
diff --git a/gcc/match.pd b/gcc/match.pd
index 2923f5b4cbe..15916800bc1 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2045,6 +2045,45 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
        (if (code1 == NE_EXPR && !val) (code1 @0 @1))))))))
 
+/* Convert (X OP1 CST1) || (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for or (truth_or bit_ior)
+   (simplify
+   (or (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Chose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	(code2 @0 @2)
+	(code1 @0 @1)))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	(code2 @0 @2)
+	(code1 @0 @1)))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LT_EXPR && code2 == GT_EXPR)
+	       || (code1 == GT_EXPR && code2 == LT_EXPR)))
+       (ne @0 @2))
+      /* Check for disjoint ranges.  */
+      (if (cmp >= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (true, type); })
+      (if (cmp <= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (true, type); })
+      ))))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 12:23                     ` Martin Liška
  2019-09-09 13:10                       ` Marc Glisse
@ 2019-09-09 13:10                       ` Richard Biener
  2019-09-09 13:40                         ` Martin Liška
  1 sibling, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-09 13:10 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 2382 bytes --]

On Mon, 9 Sep 2019, Martin Liška wrote:

> Hi.
> 
> I'm sending slightly updated version of the patch where we
> need to properly select type in maybe_fold_comparisons_from_match_pd
> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
> and so that we can't return a boolean_type_node.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
            Martin Liska  <mliska@suse.cz>

        * gimple.h (gimple_init): Declare.
        (gimple_size): Likewise.
        * gimple.c (gimple_init): Remove static and inline restrictions.
        (gimple_alloc): Only allocate memory and call gimple_init.
        (gimple_size): Likewise.

Likewise?

        * tree-ssanames.c (init_ssa_name_imm_use): Use make_ssa_name_fn.
        (make_ssa_name_fn): New.

You didn't touch make_ssa_name_fn.

Since we're needing another iteration:

+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size 
(GIMPLE_ASSIGN, 2));

You can use gassign *stmt1 here so all the gimple_assign_ fns below
get cheaper.

+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+       {
+         tree res = op.ops[0];
+         switch (TREE_CODE (res))
+           {
+           case SSA_NAME:
+               {
+                 gimple *def = SSA_NAME_DEF_STMT (res);

you shouldn't expand SSA names here unless that SSA name is
exactly lhs1 or lhs2 from above.  So

         if (res == lhs1)
           return build2 (...);
         else if (res == lhs2)
           return build2 (..);
         else
           return res;

plus you miss the case where 'op' became a simplified comparison
in itself.  So,

     if (op.code.is_tree_code ()
         && TREE_CODE_CLASS ((enum tree_code)op.code) == tcc_comparison)
       {
          tree op0 = op.ops[0];
          tree op1 = op.ops[1];
          if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
            return NULL_TREE;  /* not simple */
          return build2 ((enum tree_code)op.code, op.type,
                         op0, op1);
       }

note you need not fold_ again.  It's of course ugly that we
need to build a GENERIC tree here but that's the current interface
and thus OK at the moment.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 12:23                     ` Martin Liška
@ 2019-09-09 13:10                       ` Marc Glisse
  2019-09-09 13:30                         ` Martin Liška
  2019-09-09 13:10                       ` Richard Biener
  1 sibling, 1 reply; 56+ messages in thread
From: Marc Glisse @ 2019-09-09 13:10 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

On Mon, 9 Sep 2019, Martin Liška wrote:

> I'm sending slightly updated version of the patch where we
> need to properly select type in maybe_fold_comparisons_from_match_pd
> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
> and so that we can't return a boolean_type_node.

+  tree type = TREE_TYPE (op1a);
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    type = boolean_type_node;

Don't you need build_same_sized_truth_vector_type or something, for 
instance with AVX512?

Also, IIRC EQ_EXPR for vectors can return either a vector or a boolean. I 
don't know if we can end up here with both versions, but if we can, 
guessing the type could be dangerous. Would it be hard to add a type 
argument to those functions and delegate this to the caller? Any better 
idea (maybe this is already safe and I am just missing it)?

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:10                       ` Marc Glisse
@ 2019-09-09 13:30                         ` Martin Liška
  2019-09-09 13:39                           ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 13:30 UTC (permalink / raw)
  To: gcc-patches, Marc Glisse
  Cc: Richard Biener, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/9/19 3:10 PM, Marc Glisse wrote:
> On Mon, 9 Sep 2019, Martin Liška wrote:
> 
>> I'm sending slightly updated version of the patch where we
>> need to properly select type in maybe_fold_comparisons_from_match_pd
>> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
>> and so that we can't return a boolean_type_node.
> 
> +  tree type = TREE_TYPE (op1a);
> +  if (TREE_CODE (type) != VECTOR_TYPE)
> +    type = boolean_type_node;
> 
> Don't you need build_same_sized_truth_vector_type or something, for instance with AVX512?
> 
> Also, IIRC EQ_EXPR for vectors can return either a vector or a boolean. I don't know if we can end up here with both versions, but if we can, guessing the type could be dangerous. Would it be hard to add a type argument to those functions and delegate this to the caller? Any better idea (maybe this is already safe and I am just missing it)?

Richi can you help us here? I'm not sure what guarantees do we have here in GIMPLE?

Martin

> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:30                         ` Martin Liška
@ 2019-09-09 13:39                           ` Richard Biener
  0 siblings, 0 replies; 56+ messages in thread
From: Richard Biener @ 2019-09-09 13:39 UTC (permalink / raw)
  To: Martin Liška
  Cc: gcc-patches, Marc Glisse, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 1545 bytes --]

On Mon, 9 Sep 2019, Martin Liška wrote:

> On 9/9/19 3:10 PM, Marc Glisse wrote:
> > On Mon, 9 Sep 2019, Martin Liška wrote:
> > 
> >> I'm sending slightly updated version of the patch where we
> >> need to properly select type in maybe_fold_comparisons_from_match_pd
> >> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
> >> and so that we can't return a boolean_type_node.
> > 
> > +  tree type = TREE_TYPE (op1a);
> > +  if (TREE_CODE (type) != VECTOR_TYPE)
> > +    type = boolean_type_node;
> > 
> > Don't you need build_same_sized_truth_vector_type or something, for instance with AVX512?
> > 
> > Also, IIRC EQ_EXPR for vectors can return either a vector or a boolean. I don't know if we can end up here with both versions, but if we can, guessing the type could be dangerous. Would it be hard to add a type argument to those functions and delegate this to the caller? Any better idea (maybe this is already safe and I am just missing it)?
> 
> Richi can you help us here? I'm not sure what guarantees do we have here in GIMPLE?

Oops, I missed this hunk - the caller needs to pass this down, but at 
least from the ifcombine use we are always coming from a if (a CMP b)
context and thus a boolean_type_node result type.  For the reassoc
case there's indeed nothing preventing from vector typed comparisons
sneaking in here, likewise recursion via or_var_with_comparison_1
might run into vectors.

Thus the toplevel interface has to pass down the (common) type of
the two comparisons.

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:10                       ` Richard Biener
@ 2019-09-09 13:40                         ` Martin Liška
  2019-09-09 13:42                           ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 13:40 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 2837 bytes --]

On 9/9/19 3:10 PM, Richard Biener wrote:
> On Mon, 9 Sep 2019, Martin Liška wrote:
> 
>> Hi.
>>
>> I'm sending slightly updated version of the patch where we
>> need to properly select type in maybe_fold_comparisons_from_match_pd
>> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
>> and so that we can't return a boolean_type_node.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
> 
> 2019-07-16  Li Jia He  <helijia@linux.ibm.com>
>             Martin Liska  <mliska@suse.cz>
> 
>         * gimple.h (gimple_init): Declare.
>         (gimple_size): Likewise.
>         * gimple.c (gimple_init): Remove static and inline restrictions.
>         (gimple_alloc): Only allocate memory and call gimple_init.
>         (gimple_size): Likewise.
> 
> Likewise?

Fixed.

> 
>         * tree-ssanames.c (init_ssa_name_imm_use): Use make_ssa_name_fn.
>         (make_ssa_name_fn): New.
> 
> You didn't touch make_ssa_name_fn.

Likewise here.

> 
> Since we're needing another iteration:
> 
> +  /* Allocate gimple stmt1 on the stack.  */
> +  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size 
> (GIMPLE_ASSIGN, 2));
> 
> You can use gassign *stmt1 here so all the gimple_assign_ fns below
> get cheaper.
> 
> +  if (op.resimplify (NULL, follow_all_ssa_edges))
> +    {
> +      if (gimple_simplified_result_is_gimple_val (&op))
> +       {
> +         tree res = op.ops[0];
> +         switch (TREE_CODE (res))
> +           {
> +           case SSA_NAME:
> +               {
> +                 gimple *def = SSA_NAME_DEF_STMT (res);
> 
> you shouldn't expand SSA names here unless that SSA name is
> exactly lhs1 or lhs2 from above.  So

Ah, got it.

> 
>          if (res == lhs1)
>            return build2 (...);
>          else if (res == lhs2)
>            return build2 (..);
>          else
>            return res;
> 
> plus you miss the case where 'op' became a simplified comparison
> in itself.  So,

Yes, that part is included in part 3. I'm going to send the updated patch
3 as well soon.

> 
>      if (op.code.is_tree_code ()
>          && TREE_CODE_CLASS ((enum tree_code)op.code) == tcc_comparison)
>        {
>           tree op0 = op.ops[0];
>           tree op1 = op.ops[1];
>           if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
>             return NULL_TREE;  /* not simple */
>           return build2 ((enum tree_code)op.code, op.type,
>                          op0, op1);
>        }
> 
> note you need not fold_ again.  It's of course ugly that we
> need to build a GENERIC tree here but that's the current interface
> and thus OK at the moment.

I see. But what I need is to insert newly created GIMPLE assignment to
the provided gimple sequence (gsi), right?

Thanks,
Martin

> 
> Thanks,
> Richard.
> 


[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 10247 bytes --]

From a0b4daec604ee92ac8e76e416cd912d7d176a811 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/5] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple.h (gimple_init): Declare.
	(gimple_size): Likewise.
	* gimple.c (gimple_init): Remove static and inline restrictions.
	(gimple_alloc): Only allocate memory and call gimple_init.
	(gimple_size): Make it external and add new num_ops argument.
	* gimple-fold.c (maybe_fold_comparisons_from_match_pd): New function.
	(maybe_fold_and_comparisons): Modify and_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Modify or_comparisons_1 invocation and
	call maybe_fold_comparisons_from_match_pd.
	* tree-ssanames.c (init_ssa_name_imm_use): New.
	(make_ssa_name_fn): Use make_ssa_name_fn.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c   | 108 ++++++++++++++++++++++++++++++++++++++++----
 gcc/gimple.c        |  37 +++++++++------
 gcc/gimple.h        |   2 +
 gcc/tree-ssanames.c |  21 ++++++---
 gcc/tree-ssanames.h |   1 +
 5 files changed, 138 insertions(+), 31 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..50cb3bf7e32 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5834,6 +5834,85 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  tree type = TREE_TYPE (op1a);
+  if (TREE_CODE (type) != VECTOR_TYPE)
+    type = boolean_type_node;
+
+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gimple *stmt2 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = type;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = type;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      type, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  switch (TREE_CODE (res))
+	    {
+	    case SSA_NAME:
+		{
+		  if (res == lhs1)
+		    return build2 (code1, type, op1a, op1b);
+		  else if (res == lhs2)
+		    return build2 (code2, type, op2a, op2b);
+		  else
+		    return res;
+		}
+	    case INTEGER_CST:
+	      /* Fold expression to boolean_true_node or boolean_false_node.  */
+	      return res;
+	    default:
+	      return NULL_TREE;
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5845,11 +5924,17 @@ tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -6309,13 +6394,18 @@ tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-09 12:24                     ` [PATCH 3/5] Rewrite part of and_comparisons_1 " Martin Liška
@ 2019-09-09 13:41                       ` Martin Liška
  2019-09-10  7:41                         ` Martin Liška
  2019-09-10  8:52                         ` Bernhard Reutner-Fischer
  0 siblings, 2 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-09 13:41 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 307 bytes --]

On 9/9/19 2:24 PM, Martin Liška wrote:
> Hi.
> 
> The patch is about transition of and_comparisons_1 matching
> into match.pd.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Thanks,
> Martin
> 

Updated version (as mentioned in part 1).

Martin

[-- Attachment #2: 0003-Rewrite-part-of-and_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 25711 bytes --]

From a4127ffe3d55c67dc8ef78d62a27277807740995 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* genmatch.c (dt_node::append_simplify): Ignore warning
	for the same location.
	* gimple-fold.c (same_bool_result_p): Handle newly
	created SSA_NAMEs ar arguments.
	(and_comparisons_1): Add new argument gimple_stmt_iterator.
	(and_var_with_comparison): Likewise.
	(and_var_with_comparison_1): Likewise.
	(or_comparisons_1): Likewise.
	(or_var_with_comparison): Likewise.
	(or_var_with_comparison_1): Likewise.
	(maybe_fold_comparisons_from_match_pd): Handle creation
	of temporary SSA_NAMEs. Add new argument gimple_stmt_iterator.
	(maybe_fold_and_comparisons): Likewise.
	(maybe_fold_or_comparisons): Likewise.
	* gimple-fold.h (maybe_fold_and_comparisons): Likewise.
	(maybe_fold_or_comparisons): Likewise.
	* match.pd: Add rules for (X OP1 CST1) && (X OP2 CST2).
	* tree-if-conv.c (fold_or_predicates): Do not
	pass gimple_stmt_iterator.
	* tree-ssa-ifcombine.c (ifcombine_ifandif): Pass gimple_stmt_iterator.
	* tree-ssa-reassoc.c (eliminate_redundant_comparison): Do not
	pass gimple_stmt_iterator.
	(optimize_vec_cond_expr): Likewise.
---
 gcc/genmatch.c           |   4 +-
 gcc/gimple-fold.c        | 266 ++++++++++++++-------------------------
 gcc/gimple-fold.h        |   6 +-
 gcc/match.pd             |  68 ++++++++++
 gcc/tree-if-conv.c       |   2 +-
 gcc/tree-ssa-ifcombine.c |   5 +-
 gcc/tree-ssa-reassoc.c   |  11 +-
 7 files changed, 177 insertions(+), 185 deletions(-)

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..b7194448a0f 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
 			  dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+	&& s->match->location != s2->s->match->location)
       {
 	warning_at (s->match->location, "duplicate pattern");
 	warning_at (s2->s->match->location, "previous pattern defined here");
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 50cb3bf7e32..d046603fd6f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5350,6 +5350,19 @@ same_bool_result_p (const_tree op1, const_tree op2)
   if (operand_equal_p (op1, op2, 0))
     return true;
 
+  /* Function maybe_fold_comparisons_from_match_pd creates temporary
+     SSA_NAMEs.  */
+  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+    {
+      gimple *s = SSA_NAME_DEF_STMT (op2);
+      if (is_gimple_assign (s))
+	return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+				       gimple_assign_rhs1 (s),
+				       gimple_assign_rhs2 (s));
+      else
+	return false;
+    }
+
   /* Check the cases where at least one of the operands is a comparison.
      These are a bit smarter than operand_equal_p in that they apply some
      identifies on SSA_NAMEs.  */
@@ -5372,22 +5385,28 @@ same_bool_result_p (const_tree op1, const_tree op2)
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b);
+		   enum tree_code code2, tree op2a, tree op2b,
+		   gimple_stmt_iterator *gsi);
 static tree
 and_var_with_comparison (tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b);
+			 enum tree_code code2, tree op2a, tree op2b,
+			 gimple_stmt_iterator *gsi);
 static tree
 and_var_with_comparison_1 (gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b);
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi);
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b);
+		  enum tree_code code2, tree op2a, tree op2b,
+		  gimple_stmt_iterator *gsi);
 static tree
 or_var_with_comparison (tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b);
+			enum tree_code code2, tree op2a, tree op2b,
+			gimple_stmt_iterator *gsi);
 static tree
 or_var_with_comparison_1 (gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b);
+			  enum tree_code code2, tree op2a, tree op2b,
+			  gimple_stmt_iterator *gsi);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
    ssa variable VAR with the comparison specified by (OP2A CODE2 OP2B).
@@ -5396,7 +5415,8 @@ or_var_with_comparison_1 (gimple *stmt,
 
 static tree
 and_var_with_comparison (tree var, bool invert,
-			 enum tree_code code2, tree op2a, tree op2b)
+			 enum tree_code code2, tree op2a, tree op2b,
+			 gimple_stmt_iterator *gsi)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5411,9 +5431,9 @@ and_var_with_comparison (tree var, bool invert,
   if (invert)
     t = or_var_with_comparison_1 (stmt, 
 				  invert_tree_comparison (code2, false),
-				  op2a, op2b);
+				  op2a, op2b, gsi);
   else
-    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b, gsi);
   return canonicalize_bool (t, invert);
 }
 
@@ -5423,7 +5443,8 @@ and_var_with_comparison (tree var, bool invert,
 
 static tree
 and_var_with_comparison_1 (gimple *stmt,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -5456,9 +5477,7 @@ and_var_with_comparison_1 (gimple *stmt,
       tree t = and_comparisons_1 (innercode,
 				  gimple_assign_rhs1 (stmt),
 				  gimple_assign_rhs2 (stmt),
-				  code2,
-				  op2a,
-				  op2b);
+				  code2, op2a, op2b, gsi);
       if (t)
 	return t;
     }
@@ -5489,11 +5508,13 @@ and_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: and_var_with_comparison (inner2, false, code2, op2a, op2b,
+					   gsi));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: and_var_with_comparison (inner1, false, code2, op2a, op2b,
+					   gsi));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
@@ -5503,7 +5524,7 @@ and_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -5535,7 +5556,7 @@ and_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
-					      code2, op2a, op2b)))
+					      code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the AND case, where we are reassociating:
 	     (inner1 AND inner2) AND (op2a code2 op2b)
@@ -5589,7 +5610,8 @@ and_var_with_comparison_1 (gimple *stmt,
 
 static tree
 and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		   enum tree_code code2, tree op2a, tree op2b)
+		   enum tree_code code2, tree op2a, tree op2b,
+		   gimple_stmt_iterator *gsi)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -5618,136 +5640,6 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* If we have (op1a == op1b), we should either be able to
-	 return that or FALSE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-      /* Likewise if the second comparison is an == comparison.  */
-      else if (code2 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-
-      /* Same business with inequality tests.  */
-      else if (code1 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp != 0); break;
-	    case NE_EXPR: val = (cmp == 0); break;
-	    case LT_EXPR: val = (cmp >= 0); break;
-	    case GT_EXPR: val = (cmp <= 0); break;
-	    case LE_EXPR: val = (cmp > 0); break;
-	    case GE_EXPR: val = (cmp < 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp <= 0); break;
-	    case GT_EXPR: val = (cmp >= 0); break;
-	    case LE_EXPR: val = (cmp < 0); break;
-	    case GE_EXPR: val = (cmp > 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Chose the more restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Likewise chose the more restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
-		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
-	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for disjoint ranges. */
-      else if (cmp <= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_false_node;
-      else if (cmp >= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_false_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
@@ -5762,7 +5654,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b, gsi);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -5813,7 +5705,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = and_var_with_comparison (arg, invert, code2,
-						      op2a, op2b);
+						      op2a, op2b, gsi);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -5845,7 +5737,7 @@ static tree
 maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 				      tree op1a, tree op1b,
 				      enum tree_code code2, tree op2a,
-				      tree op2b)
+				      tree op2b, gimple_stmt_iterator *gsi)
 {
   tree type = TREE_TYPE (op1a);
   if (TREE_CODE (type) != VECTOR_TYPE)
@@ -5908,6 +5800,23 @@ maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 	      return NULL_TREE;
 	    }
 	}
+      else if (op.code.is_tree_code ()
+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+	{
+	  if (gsi)
+	    {
+	      tree op0 = op.ops[0];
+	      tree op1 = op.ops[1];
+	      if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
+		return NULL_TREE;  /* not simple */
+
+	      tree r = make_ssa_name (type);
+	      gassign *assign = gimple_build_assign (r, (tree_code)op.code,
+						     op0, op1);
+	      gsi_insert_before (gsi, assign, GSI_SAME_STMT);
+	      return r;
+	    }
+	}
     }
 
   return NULL_TREE;
@@ -5922,16 +5831,18 @@ maybe_fold_comparisons_from_match_pd (enum tree_code code, enum tree_code code1,
 
 tree
 maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
-			    enum tree_code code2, tree op2a, tree op2b)
+			    enum tree_code code2, tree op2a, tree op2b,
+			    gimple_stmt_iterator *gsi)
 {
-  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b,
+						     gsi))
     return t;
 
-  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, gsi))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_AND_EXPR, code1, op1a,
-						     op1b, code2, op2a, op2b))
+  if (tree t = and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, gsi))
     return t;
 
   return NULL_TREE;
@@ -5944,7 +5855,8 @@ maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
 
 static tree
 or_var_with_comparison (tree var, bool invert,
-			enum tree_code code2, tree op2a, tree op2b)
+			enum tree_code code2, tree op2a, tree op2b,
+			gimple_stmt_iterator *gsi)
 {
   tree t;
   gimple *stmt = SSA_NAME_DEF_STMT (var);
@@ -5959,9 +5871,9 @@ or_var_with_comparison (tree var, bool invert,
   if (invert)
     t = and_var_with_comparison_1 (stmt, 
 				   invert_tree_comparison (code2, false),
-				   op2a, op2b);
+				   op2a, op2b, gsi);
   else
-    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b, gsi);
   return canonicalize_bool (t, invert);
 }
 
@@ -5971,7 +5883,8 @@ or_var_with_comparison (tree var, bool invert,
 
 static tree
 or_var_with_comparison_1 (gimple *stmt,
-			  enum tree_code code2, tree op2a, tree op2b)
+			  enum tree_code code2, tree op2a, tree op2b,
+			  gimple_stmt_iterator *gsi)
 {
   tree var = gimple_assign_lhs (stmt);
   tree true_test_var = NULL_TREE;
@@ -6004,9 +5917,7 @@ or_var_with_comparison_1 (gimple *stmt,
       tree t = or_comparisons_1 (innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
-				 code2,
-				 op2a,
-				 op2b);
+				 code2, op2a, op2b, gsi);
       if (t)
 	return t;
     }
@@ -6037,11 +5948,13 @@ or_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: or_var_with_comparison (inner2, false, code2, op2a, op2b,
+					  gsi));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: or_var_with_comparison (inner1, false, code2, op2a, op2b,
+					  gsi));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
@@ -6051,7 +5964,7 @@ or_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -6083,7 +5996,7 @@ or_var_with_comparison_1 (gimple *stmt,
 	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
-					     code2, op2a, op2b)))
+					     code2, op2a, op2b, gsi)))
 	{
 	  /* Handle the OR case, where we are reassociating:
 	     (inner1 OR inner2) OR (op2a code2 op2b)
@@ -6138,7 +6051,8 @@ or_var_with_comparison_1 (gimple *stmt,
 
 static tree
 or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
-		  enum tree_code code2, tree op2a, tree op2b)
+		  enum tree_code code2, tree op2a, tree op2b,
+		  gimple_stmt_iterator *gsi)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
 
@@ -6311,7 +6225,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b, gsi);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6362,7 +6276,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (stmt)))
 			return NULL_TREE;
 		      temp = or_var_with_comparison (arg, invert, code2,
-						     op2a, op2b);
+						     op2a, op2b, gsi);
 		      if (!temp)
 			return NULL_TREE;
 		      else if (!result)
@@ -6392,16 +6306,18 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 
 tree
 maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
-			   enum tree_code code2, tree op2a, tree op2b)
+			   enum tree_code code2, tree op2a, tree op2b,
+			   gimple_stmt_iterator *gsi)
 {
-  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
+						     op1b, code2, op2a, op2b,
+						     gsi))
     return t;
 
-  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b, gsi))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (BIT_IOR_EXPR, code1, op1a,
-						     op1b, code2, op2a, op2b))
+  if (tree t = or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b, gsi))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 673d484ff52..3c2d19862a0 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -32,9 +32,11 @@ extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
 extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, 
-					enum tree_code, tree, tree);
+					enum tree_code, tree, tree,
+					gimple_stmt_iterator *gsi);
 extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
-				       enum tree_code, tree, tree);
+				       enum tree_code, tree, tree,
+				       gimple_stmt_iterator *gsi);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
 extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
 extern bool arith_overflowed_p (enum tree_code, const_tree, const_tree,
diff --git a/gcc/match.pd b/gcc/match.pd
index 28512d19b73..2c64c460fda 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1949,6 +1949,74 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (if (eqne == NE_EXPR)
       { constant_boolean_node (true, type); })))))
 
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for and (truth_and bit_and)
+   (simplify
+    (and:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) (code1 @0 @1))
+       (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+       (if (code1 == NE_EXPR && !val) (code2 @0 @2))))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for and (truth_and bit_and)
+   (simplify
+   (and (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Chose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LE_EXPR && code2 == GE_EXPR)
+	       || (code1 == GE_EXPR && code2 == LE_EXPR)))
+       (eq @0 @1))
+      /* Check for disjoint ranges.  */
+      (if (cmp <= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (false, type); })
+      (if (cmp >= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (false, type); })
+      ))))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index da67e39e03a..459cba2f752 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -437,7 +437,7 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
       tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
-					  code2, op2a, op2b);
+					  code2, op2a, op2b, NULL);
       if (t)
 	return t;
     }
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index f30816ace7b..92542817604 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -555,15 +555,16 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 	return false;
       /* Don't return false so fast, try maybe_fold_or_comparisons?  */
 
+      gimple_stmt_iterator gsi = gsi_for_stmt (inner_cond);
       if (!(t = maybe_fold_and_comparisons (inner_cond_code,
 					    gimple_cond_lhs (inner_cond),
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
 					    gimple_cond_lhs (outer_cond),
-					    gimple_cond_rhs (outer_cond))))
+					    gimple_cond_rhs (outer_cond),
+					    &gsi)))
 	{
 	  tree t1, t2;
-	  gimple_stmt_iterator gsi;
 	  bool logical_op_non_short_circuit = LOGICAL_OP_NON_SHORT_CIRCUIT;
 	  if (PARAM_VALUE (PARAM_LOGICAL_OP_NON_SHORT_CIRCUIT) != -1)
 	    logical_op_non_short_circuit
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index df76e66bccf..ae0752bb371 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -2091,11 +2091,13 @@ eliminate_redundant_comparison (enum tree_code opcode,
       if (opcode == BIT_IOR_EXPR)
 	t = maybe_fold_or_comparisons (lcode, op1, op2,
 				       rcode, gimple_assign_rhs1 (def2),
-				       gimple_assign_rhs2 (def2));
+				       gimple_assign_rhs2 (def2),
+				       NULL);
       else
 	t = maybe_fold_and_comparisons (lcode, op1, op2,
 					rcode, gimple_assign_rhs1 (def2),
-					gimple_assign_rhs2 (def2));
+					gimple_assign_rhs2 (def2),
+					NULL);
       if (!t)
 	continue;
 
@@ -3834,9 +3836,10 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 
 	  tree comb;
 	  if (opcode == BIT_AND_EXPR)
-	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1,
+					       NULL);
 	  else if (opcode == BIT_IOR_EXPR)
-	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1, NULL);
 	  else
 	    gcc_unreachable ();
 	  if (comb == NULL)
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:40                         ` Martin Liška
@ 2019-09-09 13:42                           ` Richard Biener
  2019-09-09 13:45                             ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-09 13:42 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 3066 bytes --]

On Mon, 9 Sep 2019, Martin Liška wrote:

> On 9/9/19 3:10 PM, Richard Biener wrote:
> > On Mon, 9 Sep 2019, Martin Liška wrote:
> > 
> >> Hi.
> >>
> >> I'm sending slightly updated version of the patch where we
> >> need to properly select type in maybe_fold_comparisons_from_match_pd
> >> function for the created SSA_NAMEs. We can be called for a VECTOR_TYPE
> >> and so that we can't return a boolean_type_node.
> >>
> >> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> >>
> >> Ready to be installed?
> > 
> > 2019-07-16  Li Jia He  <helijia@linux.ibm.com>
> >             Martin Liska  <mliska@suse.cz>
> > 
> >         * gimple.h (gimple_init): Declare.
> >         (gimple_size): Likewise.
> >         * gimple.c (gimple_init): Remove static and inline restrictions.
> >         (gimple_alloc): Only allocate memory and call gimple_init.
> >         (gimple_size): Likewise.
> > 
> > Likewise?
> 
> Fixed.
> 
> > 
> >         * tree-ssanames.c (init_ssa_name_imm_use): Use make_ssa_name_fn.
> >         (make_ssa_name_fn): New.
> > 
> > You didn't touch make_ssa_name_fn.
> 
> Likewise here.
> 
> > 
> > Since we're needing another iteration:
> > 
> > +  /* Allocate gimple stmt1 on the stack.  */
> > +  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size 
> > (GIMPLE_ASSIGN, 2));
> > 
> > You can use gassign *stmt1 here so all the gimple_assign_ fns below
> > get cheaper.
> > 
> > +  if (op.resimplify (NULL, follow_all_ssa_edges))
> > +    {
> > +      if (gimple_simplified_result_is_gimple_val (&op))
> > +       {
> > +         tree res = op.ops[0];
> > +         switch (TREE_CODE (res))
> > +           {
> > +           case SSA_NAME:
> > +               {
> > +                 gimple *def = SSA_NAME_DEF_STMT (res);
> > 
> > you shouldn't expand SSA names here unless that SSA name is
> > exactly lhs1 or lhs2 from above.  So
> 
> Ah, got it.
> 
> > 
> >          if (res == lhs1)
> >            return build2 (...);
> >          else if (res == lhs2)
> >            return build2 (..);
> >          else
> >            return res;
> > 
> > plus you miss the case where 'op' became a simplified comparison
> > in itself.  So,
> 
> Yes, that part is included in part 3. I'm going to send the updated patch
> 3 as well soon.
> 
> > 
> >      if (op.code.is_tree_code ()
> >          && TREE_CODE_CLASS ((enum tree_code)op.code) == tcc_comparison)
> >        {
> >           tree op0 = op.ops[0];
> >           tree op1 = op.ops[1];
> >           if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
> >             return NULL_TREE;  /* not simple */
> >           return build2 ((enum tree_code)op.code, op.type,
> >                          op0, op1);
> >        }
> > 
> > note you need not fold_ again.  It's of course ugly that we
> > need to build a GENERIC tree here but that's the current interface
> > and thus OK at the moment.
> 
> I see. But what I need is to insert newly created GIMPLE assignment to
> the provided gimple sequence (gsi), right?

There is no newly created GIMPLE?

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:42                           ` Richard Biener
@ 2019-09-09 13:45                             ` Martin Liška
  2019-09-09 13:55                               ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-09 13:45 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/9/19 3:42 PM, Richard Biener wrote:
> There is no newly created GIMPLE?

Hm, I thought from the beginning that maybe_fold_comparisons_from_match_pd
can come up with new temporary expressions that need to be inserted into
GIMPLE stream? But that's probably handled in ifcombine with:


	  t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true,
					  GSI_SAME_STMT);
?

Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:45                             ` Martin Liška
@ 2019-09-09 13:55                               ` Richard Biener
  2019-09-10  7:40                                 ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-09 13:55 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 889 bytes --]

On Mon, 9 Sep 2019, Martin Liška wrote:

> On 9/9/19 3:42 PM, Richard Biener wrote:
> > There is no newly created GIMPLE?
> 
> Hm, I thought from the beginning that maybe_fold_comparisons_from_match_pd
> can come up with new temporary expressions that need to be inserted into
> GIMPLE stream? But that's probably handled in ifcombine with:
> 
> 	  t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true,
> 					  GSI_SAME_STMT);
> ?

No, that case is done when forcing short-circuiting when there was no
simplification.  When there was a simplification we do

      if (result_inv)
        t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
      t = canonicalize_cond_expr_cond (t);
      if (!t)
        return false;

so when it is not a condition suitable for direct replacement into

      gimple_cond_set_condition_from_tree (inner_cond, t);

we fail.

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-09 13:55                               ` Richard Biener
@ 2019-09-10  7:40                                 ` Martin Liška
       [not found]                                   ` <ba4ec7b3-0d0d-ca7b-b2d9-2f34478a23f4@linux.ibm.com>
  2019-09-11 11:16                                   ` Martin Liška
  0 siblings, 2 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-10  7:40 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 1038 bytes --]

On 9/9/19 3:55 PM, Richard Biener wrote:
> On Mon, 9 Sep 2019, Martin Liška wrote:
> 
>> On 9/9/19 3:42 PM, Richard Biener wrote:
>>> There is no newly created GIMPLE?
>>
>> Hm, I thought from the beginning that maybe_fold_comparisons_from_match_pd
>> can come up with new temporary expressions that need to be inserted into
>> GIMPLE stream? But that's probably handled in ifcombine with:
>>
>> 	  t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true,
>> 					  GSI_SAME_STMT);
>> ?
> 
> No, that case is done when forcing short-circuiting when there was no
> simplification.  When there was a simplification we do
> 
>        if (result_inv)
>          t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
>        t = canonicalize_cond_expr_cond (t);
>        if (!t)
>          return false;
> 
> so when it is not a condition suitable for direct replacement into
> 
>        gimple_cond_set_condition_from_tree (inner_cond, t);
> 
> we fail.
> 
> Richard.
> 

I see, so I'm sending updated tested patch.

Martin

[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 24555 bytes --]

From f757482a57754e5c7590e0f2cadf3cc4443beab6 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/5] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (and_comparisons_1): Add type as first
	argument.
	(and_var_with_comparison): Likewise.
	(and_var_with_comparison_1): Likewise.
	(or_comparisons_1): Likewise.
	(or_var_with_comparison): Likewise.
	(or_var_with_comparison_1): Likewise.
	(maybe_fold_and_comparisons): Call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Likewise.
	(maybe_fold_comparisons_from_match_pd): New.
	* gimple-fold.h (maybe_fold_and_comparisons): Add type argument.
	(maybe_fold_or_comparisons): Likewise.
	* gimple.c (gimple_size): Make it public and add num_ops argument.
	(gimple_init): New function.
	(gimple_alloc): Call gimple_init.
	* gimple.h (gimple_size): New.
	(gimple_init): Likewise.
	* tree-if-conv.c (fold_or_predicates): Pass type.
	* tree-ssa-ifcombine.c (ifcombine_ifandif): Likewise.
	* tree-ssa-reassoc.c (eliminate_redundant_comparison): Likewise.
	(optimize_vec_cond_expr): Likewise.
	* tree-ssanames.c (init_ssa_name_imm_use): New.
	(make_ssa_name_fn): Use init_ssa_name_imm_use.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c        | 179 ++++++++++++++++++++++++++++++---------
 gcc/gimple-fold.h        |   4 +-
 gcc/gimple.c             |  37 ++++----
 gcc/gimple.h             |   2 +
 gcc/tree-if-conv.c       |   2 +-
 gcc/tree-ssa-ifcombine.c |   2 +-
 gcc/tree-ssa-reassoc.c   |  14 ++-
 gcc/tree-ssanames.c      |  21 +++--
 gcc/tree-ssanames.h      |   1 +
 9 files changed, 191 insertions(+), 71 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..fcdcb087ec4 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5371,22 +5371,22 @@ same_bool_result_p (const_tree op1, const_tree op2)
 /* Forward declarations for some mutually recursive functions.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
@@ -5395,7 +5395,7 @@ or_var_with_comparison_1 (gimple *stmt,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5409,11 +5409,11 @@ and_var_with_comparison (tree var, bool invert,
      !var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = or_var_with_comparison_1 (stmt, 
+    t = or_var_with_comparison_1 (type, stmt,
 				  invert_tree_comparison (code2, false),
 				  op2a, op2b);
   else
-    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5422,7 +5422,7 @@ and_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5453,7 +5453,7 @@ and_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = and_comparisons_1 (innercode,
+      tree t = and_comparisons_1 (type, innercode,
 				  gimple_assign_rhs1 (stmt),
 				  gimple_assign_rhs2 (stmt),
 				  code2,
@@ -5489,18 +5489,20 @@ and_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner2, false, code2, op2a,
+					   op2b));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner1, false, code2, op2a,
+					   op2b));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5532,7 +5534,7 @@ and_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5588,7 +5590,7 @@ and_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -5762,7 +5764,8 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return and_var_with_comparison (type, op1a, invert, code2, op2a,
+					  op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -5812,7 +5815,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = and_var_with_comparison (arg, invert, code2,
+		      temp = and_var_with_comparison (type, arg, invert, code2,
 						      op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -5834,6 +5837,82 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
+				      enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  /* Allocate gimple stmt1 on the stack.  */
+  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gimple *stmt2 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = type;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = type;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      type, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  switch (TREE_CODE (res))
+	    {
+	    case SSA_NAME:
+		{
+		  if (res == lhs1)
+		    return build2 (code1, type, op1a, op1b);
+		  else if (res == lhs2)
+		    return build2 (code2, type, op2a, op2b);
+		  else
+		    return res;
+		}
+	    case INTEGER_CST:
+	      /* Fold expression to boolean_true_node or boolean_false_node.  */
+	      return res;
+	    default:
+	      return NULL_TREE;
+	    }
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5842,14 +5921,22 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_and_comparisons (tree type,
+			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -5858,7 +5945,7 @@ maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree type, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5872,11 +5959,11 @@ or_var_with_comparison (tree var, bool invert,
      !var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = and_var_with_comparison_1 (stmt, 
+    t = and_var_with_comparison_1 (type, stmt,
 				   invert_tree_comparison (code2, false),
 				   op2a, op2b);
   else
-    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5885,7 +5972,7 @@ or_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree type, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5916,7 +6003,7 @@ or_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = or_comparisons_1 (innercode,
+      tree t = or_comparisons_1 (type, innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
 				 code2,
@@ -5952,18 +6039,20 @@ or_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner2, false, code2, op2a,
+					  op2b));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner1, false, code2, op2a,
+					  op2b));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -5995,7 +6084,7 @@ or_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -6052,7 +6141,7 @@ or_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -6226,7 +6315,8 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return or_var_with_comparison (type, op1a, invert, code2, op2a,
+					 op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6276,7 +6366,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = or_var_with_comparison (arg, invert, code2,
+		      temp = or_var_with_comparison (type, arg, invert, code2,
 						     op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -6306,16 +6396,23 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_or_comparisons (tree type,
+			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 673d484ff52..f9d1d54daf4 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -31,9 +31,9 @@ extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
-extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, 
+extern tree maybe_fold_and_comparisons (tree, enum tree_code, tree, tree,
 					enum tree_code, tree, tree);
-extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
+extern tree maybe_fold_or_comparisons (tree, enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
 extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index da67e39e03a..40ad4c5947a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -436,7 +436,7 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
 
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
-      tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
+      tree t = maybe_fold_or_comparisons (boolean_type_node, code1, op1a, op1b,
 					  code2, op2a, op2b);
       if (t)
 	return t;
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index f30816ace7b..90d8bb5e9e7 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -555,7 +555,7 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 	return false;
       /* Don't return false so fast, try maybe_fold_or_comparisons?  */
 
-      if (!(t = maybe_fold_and_comparisons (inner_cond_code,
+      if (!(t = maybe_fold_and_comparisons (boolean_type_node, inner_cond_code,
 					    gimple_cond_lhs (inner_cond),
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index df76e66bccf..f2fcd10b78a 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -2088,12 +2088,15 @@ eliminate_redundant_comparison (enum tree_code opcode,
 
       /* If we got here, we have a match.  See if we can combine the
 	 two comparisons.  */
+      tree type = TREE_TYPE (gimple_assign_lhs (def1));
       if (opcode == BIT_IOR_EXPR)
-	t = maybe_fold_or_comparisons (lcode, op1, op2,
+	t = maybe_fold_or_comparisons (type,
+				       lcode, op1, op2,
 				       rcode, gimple_assign_rhs1 (def2),
 				       gimple_assign_rhs2 (def2));
       else
-	t = maybe_fold_and_comparisons (lcode, op1, op2,
+	t = maybe_fold_and_comparisons (type,
+					lcode, op1, op2,
 					rcode, gimple_assign_rhs1 (def2),
 					gimple_assign_rhs2 (def2));
       if (!t)
@@ -3833,10 +3836,13 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 	  tree y1 = TREE_OPERAND (cond1, 1);
 
 	  tree comb;
+	  tree type = TREE_TYPE (gimple_assign_lhs (stmt0));
 	  if (opcode == BIT_AND_EXPR)
-	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_and_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					       y1);
 	  else if (opcode == BIT_IOR_EXPR)
-	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_or_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					      y1);
 	  else
 	    gcc_unreachable ();
 	  if (comb == NULL)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-09 13:41                       ` Martin Liška
@ 2019-09-10  7:41                         ` Martin Liška
  2019-09-10 11:19                           ` Marc Glisse
  2019-09-10  8:52                         ` Bernhard Reutner-Fischer
  1 sibling, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-10  7:41 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 494 bytes --]

On 9/9/19 3:41 PM, Martin Liška wrote:
> On 9/9/19 2:24 PM, Martin Liška wrote:
>> Hi.
>>
>> The patch is about transition of and_comparisons_1 matching
>> into match.pd.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
>> Thanks,
>> Martin
>>
> 
> Updated version (as mentioned in part 1).
> 
> Martin
> 

And there's updated part 3 where I properly handle the
TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison case.

Martin

[-- Attachment #2: 0003-Rewrite-part-of-and_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 11683 bytes --]

From 5e495f3eeeda3a2a850a3d61fbfd084b4a41328a Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* genmatch.c (dt_node::append_simplify): Do not print
	warning when we have duplicate patterns belonging
	to a same simplify rule.
	* gimple-fold.c (same_bool_result_p): Handle SSA_NAMEs
	created in maybe_fold_comparisons_from_match_pd.
	(and_comparisons_1): Remove matching moved to match.pd.
	(maybe_fold_comparisons_from_match_pd): Handle
	tcc_comparison as a results.
	(maybe_fold_and_comparisons):Call maybe_fold_comparisons_from_match_pd
	first.
	(maybe_fold_or_comparisons): Likewise.
	* match.pd: Handle (X == CST1) && (X OP2 CST2) conditions.
---
 gcc/genmatch.c    |   4 +-
 gcc/gimple-fold.c | 174 +++++++++-------------------------------------
 gcc/match.pd      |  68 ++++++++++++++++++
 3 files changed, 105 insertions(+), 141 deletions(-)

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..b7194448a0f 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
 			  dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+	&& s->match->location != s2->s->match->location)
       {
 	warning_at (s->match->location, "duplicate pattern");
 	warning_at (s2->s->match->location, "previous pattern defined here");
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcdcb087ec4..ae7a363710c 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5350,6 +5350,19 @@ same_bool_result_p (const_tree op1, const_tree op2)
   if (operand_equal_p (op1, op2, 0))
     return true;
 
+  /* Function maybe_fold_comparisons_from_match_pd creates temporary
+     SSA_NAMEs.  */
+  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+    {
+      gimple *s = SSA_NAME_DEF_STMT (op2);
+      if (is_gimple_assign (s))
+	return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+				       gimple_assign_rhs1 (s),
+				       gimple_assign_rhs2 (s));
+      else
+	return false;
+    }
+
   /* Check the cases where at least one of the operands is a comparison.
      These are a bit smarter than operand_equal_p in that they apply some
      identifies on SSA_NAMEs.  */
@@ -5620,136 +5633,6 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* If we have (op1a == op1b), we should either be able to
-	 return that or FALSE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-      /* Likewise if the second comparison is an == comparison.  */
-      else if (code2 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-
-      /* Same business with inequality tests.  */
-      else if (code1 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp != 0); break;
-	    case NE_EXPR: val = (cmp == 0); break;
-	    case LT_EXPR: val = (cmp >= 0); break;
-	    case GT_EXPR: val = (cmp <= 0); break;
-	    case LE_EXPR: val = (cmp > 0); break;
-	    case GE_EXPR: val = (cmp < 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp <= 0); break;
-	    case GT_EXPR: val = (cmp >= 0); break;
-	    case LE_EXPR: val = (cmp < 0); break;
-	    case GE_EXPR: val = (cmp > 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Chose the more restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Likewise chose the more restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
-		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
-	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for disjoint ranges. */
-      else if (cmp <= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_false_node;
-      else if (cmp >= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_false_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
@@ -5908,6 +5791,16 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
 	      return NULL_TREE;
 	    }
 	}
+      else if (op.code.is_tree_code ()
+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+	{
+	  tree op0 = op.ops[0];
+	  tree op1 = op.ops[1];
+	  if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
+	    return NULL_TREE;  /* not simple */
+
+	  return build2 ((enum tree_code)op.code, op.type, op0, op1);
+	}
     }
 
   return NULL_TREE;
@@ -5925,17 +5818,18 @@ maybe_fold_and_comparisons (tree type,
 			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
-    return t;
-
-  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
-    return t;
 
   if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
 						     op1a, op1b, code2, op2a,
 						     op2b))
     return t;
 
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
   return NULL_TREE;
 }
 
@@ -6400,15 +6294,15 @@ maybe_fold_or_comparisons (tree type,
 			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
     return t;
 
-  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
-						     op1a, op1b, code2, op2a,
-						     op2b))
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/match.pd b/gcc/match.pd
index 28512d19b73..2c64c460fda 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1949,6 +1949,74 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (if (eqne == NE_EXPR)
       { constant_boolean_node (true, type); })))))
 
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for and (truth_and bit_and)
+   (simplify
+    (and:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) (code1 @0 @1))
+       (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+       (if (code1 == NE_EXPR && !val) (code2 @0 @2))))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for and (truth_and bit_and)
+   (simplify
+   (and (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Chose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	(code1 @0 @1)
+	(code2 @0 @2)))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LE_EXPR && code2 == GE_EXPR)
+	       || (code1 == GE_EXPR && code2 == LE_EXPR)))
+       (eq @0 @1))
+      /* Check for disjoint ranges.  */
+      (if (cmp <= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (false, type); })
+      (if (cmp >= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (false, type); })
+      ))))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-09 13:41                       ` Martin Liška
  2019-09-10  7:41                         ` Martin Liška
@ 2019-09-10  8:52                         ` Bernhard Reutner-Fischer
  2019-09-11  8:11                           ` Martin Liška
  1 sibling, 1 reply; 56+ messages in thread
From: Bernhard Reutner-Fischer @ 2019-09-10  8:52 UTC (permalink / raw)
  To: gcc-patches, Martin Liška, Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

On 9 September 2019 15:41:05 CEST, "Martin Liška" <mliska@suse.cz> wrote:
>On 9/9/19 2:24 PM, Martin Liška wrote:
>> Hi.
>> 
>> The patch is about transition of and_comparisons_1 matching
>> into match.pd.
>> 
>> Patch can bootstrap on x86_64-linux-gnu and survives regression
>tests.
>> 
>> Ready to be installed?
>> Thanks,
>> Martin
>> 
>
>Updated version (as mentioned in part 1).
>

+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)

COMPARISON_CLASS_P

thanks,

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-10  7:41                         ` Martin Liška
@ 2019-09-10 11:19                           ` Marc Glisse
  2019-09-11  8:27                             ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Marc Glisse @ 2019-09-10 11:19 UTC (permalink / raw)
  To: Martin Liška
  Cc: Richard Biener, Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

(some quick comments, I didn't check in details)

+    (and:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
[...]
+       (if (code1 == NE_EXPR && !val) (code2 @0 @2))))))))

How about

(and:c (code1 @0 INTEGER_CST@1) (code2@3 @0 INTEGER_CST@2))
[...]
(if (code1 == NE_EXPR && !val) @3)))))))

instead? This is also a way to check how well the generator handles this, 
when @3 may not really exist (was in a gimple_cond).

(and:c (eq@3 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))

could be simplified to

(and @3 (code2 @1 @2))

always (a trivial transform) and let the rest of the machinery fold code2 
on constants and then and with a constant. This way you would only need to 
handle code1==NE_EXPR in the complicated transform, it might be slightly 
more readable. (I am not saying we absolutely have to do it this way, it 
is just a suggestion)

+   (and (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))

Don't we canonicalize 3 < X to X > 3? That would make the :c unnecessary. 
Actually I don't remember how :c works on non-commutative operations 
(there was also :C I think).

+      /* Chose the more restrictive of two < or <= comparisons.  */

Choose?

-- 
Marc Glisse

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-10  8:52                         ` Bernhard Reutner-Fischer
@ 2019-09-11  8:11                           ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-11  8:11 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer, gcc-patches, Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, Segher Boessenkool, wschmidt, Martin Liska

On 9/10/19 10:52 AM, Bernhard Reutner-Fischer wrote:
> On 9 September 2019 15:41:05 CEST, "Martin Liška" <mliska@suse.cz> wrote:
>> On 9/9/19 2:24 PM, Martin Liška wrote:
>>> Hi.
>>>
>>> The patch is about transition of and_comparisons_1 matching
>>> into match.pd.
>>>
>>> Patch can bootstrap on x86_64-linux-gnu and survives regression
>> tests.
>>>
>>> Ready to be installed?
>>> Thanks,
>>> Martin
>>>
>>
>> Updated version (as mentioned in part 1).
>>
> 
> +	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
> 
> COMPARISON_CLASS_P
> 
> thanks,
> 

Thanks for the comment.

Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-10 11:19                           ` Marc Glisse
@ 2019-09-11  8:27                             ` Martin Liška
  2019-09-11 11:18                               ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11  8:27 UTC (permalink / raw)
  To: gcc-patches
  Cc: Richard Biener, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/10/19 1:19 PM, Marc Glisse wrote:
> (some quick comments, I didn't check in details)

Thanks for them.

> 
> +    (and:c (code1 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
> [...]
> +       (if (code1 == NE_EXPR && !val) (code2 @0 @2))))))))
> 
> How about
> 
> (and:c (code1 @0 INTEGER_CST@1) (code2@3 @0 INTEGER_CST@2))
> [...]
> (if (code1 == NE_EXPR && !val) @3)))))))
> 
> instead? This is also a way to check how well the generator handles this, when @3 may not really exist (was in a gimple_cond).

I like the changes. I applied them to all patterns in the patch set.

> 
> (and:c (eq@3 @0 INTEGER_CST@1) (code2 @0 INTEGER_CST@2))
> 
> could be simplified to
> 
> (and @3 (code2 @1 @2))
> 
> always (a trivial transform) and let the rest of the machinery fold code2 on constants and then and with a constant. This way you would only need to handle code1==NE_EXPR in the complicated transform, it might be slightly more readable. (I am not saying we absolutely have to do it this way, it is just a suggestion)

That would be possible, I can experiment with that after the patch set is applied.
The current patch is more or less direct transformation of what we have in gimple-fold.c.
> 
> +   (and (code1:c @0 INTEGER_CST@1) (code2:c @0 INTEGER_CST@2))
> 
> Don't we canonicalize 3 < X to X > 3? That would make the :c unnecessary. Actually I don't remember how :c works on non-commutative operations (there was also :C I think).

Dunno here, Richi?

> 
> +      /* Chose the more restrictive of two < or <= comparisons.  */
> 
> Choose?

Yep.

Thank you,
Martin

> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
       [not found]                                   ` <ba4ec7b3-0d0d-ca7b-b2d9-2f34478a23f4@linux.ibm.com>
@ 2019-09-11  8:51                                     ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-11  8:51 UTC (permalink / raw)
  To: Li Jia He; +Cc: GCC Patches

On 9/11/19 10:22 AM, Li Jia He wrote:
> Hi,
> 
> On 2019/9/10 3:40 PM, Martin Liška wrote:
>> On 9/9/19 3:55 PM, Richard Biener wrote:
>>> On Mon, 9 Sep 2019, Martin Liška wrote:
>>>
>>>> On 9/9/19 3:42 PM, Richard Biener wrote:
>>>>> There is no newly created GIMPLE?
>>>>
>>>> Hm, I thought from the beginning that maybe_fold_comparisons_from_match_pd
>>>> can come up with new temporary expressions that need to be inserted into
>>>> GIMPLE stream? But that's probably handled in ifcombine with:
>>>>
>>>>       t = force_gimple_operand_gsi_1 (&gsi, t, is_gimple_condexpr, NULL, true,
>>>>                       GSI_SAME_STMT);
>>>> ?
>>>
>>> No, that case is done when forcing short-circuiting when there was no
>>> simplification.  When there was a simplification we do
>>>
>>>        if (result_inv)
>>>          t = fold_build1 (TRUTH_NOT_EXPR, TREE_TYPE (t), t);
>>>        t = canonicalize_cond_expr_cond (t);
>>>        if (!t)
>>>          return false;
>>>
>>> so when it is not a condition suitable for direct replacement into
>>>
>>>        gimple_cond_set_condition_from_tree (inner_cond, t);
>>>
>>> we fail.
>>>
>>> Richard.
>>>
>>
>> I see, so I'm sending updated tested patch.
> 

Hello.

Next time, please Reply to all ;)

> Thanks for working on this.
> I tested the patch.  But I found that this patch will cause gcc not to bootstrap.  I found the following statement may be a question.
> '
> gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
> '
> we may need to change it to the following
> '
> gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
> '
> And we may also replace gimple with gassign.

Good point, I'll include the changes to my patchset.

> 
> And we may also need to make some changes to the statements in
> if(op.resimplify (NULL, follow_all_ssa_edges)).  Please take a look at the attachment:

@@ -5888,23 +5890,22 @@

 maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,

       if (gimple_simplified_result_is_gimple_val (&op)) 
 	{ 
 	  tree res = op.ops[0]; 
-	  switch (TREE_CODE (res)) 
-	    { 
-	    case SSA_NAME: 
-		{ 
-		  if (res == lhs1) 
-		    return build2 (code1, type, op1a, op1b); 
-		  else if (res == lhs2) 
-		    return build2 (code2, type, op2a, op2b); 
-		  else 
-		    return res; 
-		} 
-	    case INTEGER_CST: 
-	      /* Fold expression to boolean_true_node or boolean_false_node.  */ 
-	      return res; 
-	    default: 
-	      return NULL_TREE; 
-	    } 
+	  if (res == lhs1) 
+	    return build2 (code1, type, op1a, op1b); 
+	  else if (res == lhs2) 
+	    return build2 (code2, type, op2a, op2b); 
+	  else 
+	    return res; 

I'll include this.

+	} 
+ 
+      if (op.code.is_tree_code () 
+	  && TREE_CODE_CLASS ((enum tree_code) op.code) == tcc_comparison) 
+	{ 
+	  tree op0 = op.ops[0]; 
+	  tree op1 = op.ops[1]; 
+	  if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2) 
+	    return NULL_TREE; /* not simple */ 
+	  return build2 ((enum tree_code) op.code, op.type, op0, op1); 
 	} 
     } 

This is added in patch 3/5.

Martin

> 
> Thanks,
> Lijia He
> 
>>
>> Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-10  7:40                                 ` Martin Liška
       [not found]                                   ` <ba4ec7b3-0d0d-ca7b-b2d9-2f34478a23f4@linux.ibm.com>
@ 2019-09-11 11:16                                   ` Martin Liška
  2019-09-11 12:23                                     ` Richard Biener
  1 sibling, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 11:16 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 461 bytes --]

Hello.

One another updated version of the patch.
Changes from the previous version:
- I fixed:
  gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
  into gimple_size (GIMPLE_ASSIGN, 3)
- I simplified condition in gimple_simplified_result_is_gimple_val
- optimize_vec_cond_expr is using build_same_sized_truth_vector_type

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 24383 bytes --]

From ee44ff1742928e3200ce6a0677e8c8a3dbe4e6d2 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/5] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (and_comparisons_1): Add type as first
	argument.
	(and_var_with_comparison): Likewise.
	(and_var_with_comparison_1): Likewise.
	(or_comparisons_1): Likewise.
	(or_var_with_comparison): Likewise.
	(or_var_with_comparison_1): Likewise.
	(maybe_fold_and_comparisons): Call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Likewise.
	(maybe_fold_comparisons_from_match_pd): New.
	* gimple-fold.h (maybe_fold_and_comparisons): Add type argument.
	(maybe_fold_or_comparisons): Likewise.
	* gimple.c (gimple_size): Make it public and add num_ops argument.
	(gimple_init): New function.
	(gimple_alloc): Call gimple_init.
	* gimple.h (gimple_size): New.
	(gimple_init): Likewise.
	* tree-if-conv.c (fold_or_predicates): Pass type.
	* tree-ssa-ifcombine.c (ifcombine_ifandif): Likewise.
	* tree-ssa-reassoc.c (eliminate_redundant_comparison): Likewise.
	(optimize_vec_cond_expr): Likewise.
	* tree-ssanames.c (init_ssa_name_imm_use): New.
	(make_ssa_name_fn): Use init_ssa_name_imm_use.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c        | 170 +++++++++++++++++++++++++++++----------
 gcc/gimple-fold.h        |   4 +-
 gcc/gimple.c             |  37 +++++----
 gcc/gimple.h             |   2 +
 gcc/tree-if-conv.c       |   2 +-
 gcc/tree-ssa-ifcombine.c |   2 +-
 gcc/tree-ssa-reassoc.c   |  15 +++-
 gcc/tree-ssanames.c      |  21 +++--
 gcc/tree-ssanames.h      |   1 +
 9 files changed, 183 insertions(+), 71 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..aa2f94ace28 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5371,22 +5371,22 @@ same_bool_result_p (const_tree op1, const_tree op2)
 /* Forward declarations for some mutually recursive functions.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
@@ -5395,7 +5395,7 @@ or_var_with_comparison_1 (gimple *stmt,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5409,11 +5409,11 @@ and_var_with_comparison (tree var, bool invert,
      !var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = or_var_with_comparison_1 (stmt, 
+    t = or_var_with_comparison_1 (type, stmt,
 				  invert_tree_comparison (code2, false),
 				  op2a, op2b);
   else
-    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5422,7 +5422,7 @@ and_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5453,7 +5453,7 @@ and_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = and_comparisons_1 (innercode,
+      tree t = and_comparisons_1 (type, innercode,
 				  gimple_assign_rhs1 (stmt),
 				  gimple_assign_rhs2 (stmt),
 				  code2,
@@ -5489,18 +5489,20 @@ and_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner2, false, code2, op2a,
+					   op2b));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner1, false, code2, op2a,
+					   op2b));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5532,7 +5534,7 @@ and_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5588,7 +5590,7 @@ and_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -5762,7 +5764,8 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return and_var_with_comparison (type, op1a, invert, code2, op2a,
+					  op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -5812,7 +5815,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = and_var_with_comparison (arg, invert, code2,
+		      temp = and_var_with_comparison (type, arg, invert, code2,
 						      op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -5834,6 +5837,73 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
+				      enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  /* Allocate gimple stmt1 on the stack.  */
+  gassign *stmt1 =
+    (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gassign *stmt2
+    = (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = type;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = type;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      type, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  if (res == lhs1)
+	    return build2 (code1, type, op1a, op1b);
+	  else if (res == lhs2)
+	    return build2 (code2, type, op2a, op2b);
+	  else
+	    return res;
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5842,14 +5912,22 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_and_comparisons (tree type,
+			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -5858,7 +5936,7 @@ maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree type, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5872,11 +5950,11 @@ or_var_with_comparison (tree var, bool invert,
      !var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = and_var_with_comparison_1 (stmt, 
+    t = and_var_with_comparison_1 (type, stmt,
 				   invert_tree_comparison (code2, false),
 				   op2a, op2b);
   else
-    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5885,7 +5963,7 @@ or_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree type, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5916,7 +5994,7 @@ or_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = or_comparisons_1 (innercode,
+      tree t = or_comparisons_1 (type, innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
 				 code2,
@@ -5952,18 +6030,20 @@ or_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner2, false, code2, op2a,
+					  op2b));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner1, false, code2, op2a,
+					  op2b));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -5995,7 +6075,7 @@ or_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -6052,7 +6132,7 @@ or_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -6226,7 +6306,8 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return or_var_with_comparison (type, op1a, invert, code2, op2a,
+					 op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6276,7 +6357,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = or_var_with_comparison (arg, invert, code2,
+		      temp = or_var_with_comparison (type, arg, invert, code2,
 						     op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -6306,16 +6387,23 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_or_comparisons (tree type,
+			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 673d484ff52..f9d1d54daf4 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -31,9 +31,9 @@ extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
-extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, 
+extern tree maybe_fold_and_comparisons (tree, enum tree_code, tree, tree,
 					enum tree_code, tree, tree);
-extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
+extern tree maybe_fold_or_comparisons (tree, enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
 extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index da67e39e03a..40ad4c5947a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -436,7 +436,7 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
 
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
-      tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
+      tree t = maybe_fold_or_comparisons (boolean_type_node, code1, op1a, op1b,
 					  code2, op2a, op2b);
       if (t)
 	return t;
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index f30816ace7b..90d8bb5e9e7 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -555,7 +555,7 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 	return false;
       /* Don't return false so fast, try maybe_fold_or_comparisons?  */
 
-      if (!(t = maybe_fold_and_comparisons (inner_cond_code,
+      if (!(t = maybe_fold_and_comparisons (boolean_type_node, inner_cond_code,
 					    gimple_cond_lhs (inner_cond),
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index df76e66bccf..a68543edde4 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -2088,12 +2088,15 @@ eliminate_redundant_comparison (enum tree_code opcode,
 
       /* If we got here, we have a match.  See if we can combine the
 	 two comparisons.  */
+      tree type = TREE_TYPE (gimple_assign_lhs (def1));
       if (opcode == BIT_IOR_EXPR)
-	t = maybe_fold_or_comparisons (lcode, op1, op2,
+	t = maybe_fold_or_comparisons (type,
+				       lcode, op1, op2,
 				       rcode, gimple_assign_rhs1 (def2),
 				       gimple_assign_rhs2 (def2));
       else
-	t = maybe_fold_and_comparisons (lcode, op1, op2,
+	t = maybe_fold_and_comparisons (type,
+					lcode, op1, op2,
 					rcode, gimple_assign_rhs1 (def2),
 					gimple_assign_rhs2 (def2));
       if (!t)
@@ -3833,10 +3836,14 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 	  tree y1 = TREE_OPERAND (cond1, 1);
 
 	  tree comb;
+	  tree type = TREE_TYPE (gimple_assign_lhs (stmt0));
+	  type = build_same_sized_truth_vector_type (type);
 	  if (opcode == BIT_AND_EXPR)
-	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_and_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					       y1);
 	  else if (opcode == BIT_IOR_EXPR)
-	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_or_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					      y1);
 	  else
 	    gcc_unreachable ();
 	  if (comb == NULL)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-11  8:27                             ` Martin Liška
@ 2019-09-11 11:18                               ` Martin Liška
  2019-09-11 12:44                                 ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 11:18 UTC (permalink / raw)
  To: gcc-patches
  Cc: Richard Biener, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 307 bytes --]

I'm sending updated version of the patch where I changed
from previous version:
- more compact matching is used (note @3 and @4):
  (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0003-Rewrite-part-of-and_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 11619 bytes --]

From e21404f55f51701d25a6d859b892b219d2041e02 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* genmatch.c (dt_node::append_simplify): Do not print
	warning when we have duplicate patterns belonging
	to a same simplify rule.
	* gimple-fold.c (same_bool_result_p): Handle SSA_NAMEs
	created in maybe_fold_comparisons_from_match_pd.
	(and_comparisons_1): Remove matching moved to match.pd.
	(maybe_fold_comparisons_from_match_pd): Handle
	tcc_comparison as a results.
	(maybe_fold_and_comparisons):Call maybe_fold_comparisons_from_match_pd
	first.
	(maybe_fold_or_comparisons): Likewise.
	* match.pd: Handle (X == CST1) && (X OP2 CST2) conditions.
---
 gcc/genmatch.c    |   4 +-
 gcc/gimple-fold.c | 174 +++++++++-------------------------------------
 gcc/match.pd      |  68 ++++++++++++++++++
 3 files changed, 105 insertions(+), 141 deletions(-)

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..b7194448a0f 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
 			  dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+	&& s->match->location != s2->s->match->location)
       {
 	warning_at (s->match->location, "duplicate pattern");
 	warning_at (s2->s->match->location, "previous pattern defined here");
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index aa2f94ace28..58235d613d3 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5350,6 +5350,19 @@ same_bool_result_p (const_tree op1, const_tree op2)
   if (operand_equal_p (op1, op2, 0))
     return true;
 
+  /* Function maybe_fold_comparisons_from_match_pd creates temporary
+     SSA_NAMEs.  */
+  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+    {
+      gimple *s = SSA_NAME_DEF_STMT (op2);
+      if (is_gimple_assign (s))
+	return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+				       gimple_assign_rhs1 (s),
+				       gimple_assign_rhs2 (s));
+      else
+	return false;
+    }
+
   /* Check the cases where at least one of the operands is a comparison.
      These are a bit smarter than operand_equal_p in that they apply some
      identifies on SSA_NAMEs.  */
@@ -5620,136 +5633,6 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* If we have (op1a == op1b), we should either be able to
-	 return that or FALSE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-      /* Likewise if the second comparison is an == comparison.  */
-      else if (code2 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-
-      /* Same business with inequality tests.  */
-      else if (code1 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp != 0); break;
-	    case NE_EXPR: val = (cmp == 0); break;
-	    case LT_EXPR: val = (cmp >= 0); break;
-	    case GT_EXPR: val = (cmp <= 0); break;
-	    case LE_EXPR: val = (cmp > 0); break;
-	    case GE_EXPR: val = (cmp < 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp <= 0); break;
-	    case GT_EXPR: val = (cmp >= 0); break;
-	    case LE_EXPR: val = (cmp < 0); break;
-	    case GE_EXPR: val = (cmp > 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Chose the more restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Likewise chose the more restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
-		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
-	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for disjoint ranges. */
-      else if (cmp <= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_false_node;
-      else if (cmp >= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_false_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
@@ -5899,6 +5782,16 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
 	  else
 	    return res;
 	}
+      else if (op.code.is_tree_code ()
+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+	{
+	  tree op0 = op.ops[0];
+	  tree op1 = op.ops[1];
+	  if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
+	    return NULL_TREE;  /* not simple */
+
+	  return build2 ((enum tree_code)op.code, op.type, op0, op1);
+	}
     }
 
   return NULL_TREE;
@@ -5916,17 +5809,18 @@ maybe_fold_and_comparisons (tree type,
 			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
-    return t;
-
-  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
-    return t;
 
   if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
 						     op1a, op1b, code2, op2a,
 						     op2b))
     return t;
 
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
   return NULL_TREE;
 }
 
@@ -6391,15 +6285,15 @@ maybe_fold_or_comparisons (tree type,
 			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
     return t;
 
-  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
-						     op1a, op1b, code2, op2a,
-						     op2b))
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/match.pd b/gcc/match.pd
index 0e557025b34..008b93d906f 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1967,6 +1967,74 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
      (if (eqne == NE_EXPR)
       { constant_boolean_node (true, type); })))))
 
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for and (truth_and bit_and)
+   (simplify
+    (and:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) @3)
+       (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+       (if (code1 == NE_EXPR && !val) @4)))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for and (truth_and bit_and)
+   (simplify
+   (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Choose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	@3
+	@4))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	@3
+	@4))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LE_EXPR && code2 == GE_EXPR)
+	       || (code1 == GE_EXPR && code2 == LE_EXPR)))
+       (eq @0 @1))
+      /* Check for disjoint ranges.  */
+      (if (cmp <= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (false, type); })
+      (if (cmp >= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (false, type); })
+      ))))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.
  2019-09-09 12:25                     ` [PATCH 5/5] Rewrite second part of or_comparisons_1 " Martin Liška
@ 2019-09-11 11:19                       ` Martin Liška
  2019-09-11 13:57                         ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 11:19 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 197 bytes --]

Hi.

There's slightly updated version of the patch where
I use @3 and @4 in match.pd.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0005-Rewrite-second-part-of-or_comparisons_1-into-match.p.patch --]
[-- Type: text/x-patch, Size: 4478 bytes --]

From 00f3638c4ecf711edba9a92931a0835ab476c28c Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:59:36 +0200
Subject: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules moved
	to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 45 ---------------------------------------------
 gcc/match.pd      | 39 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 39 insertions(+), 45 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 5931cf3df0a..1c598564d5e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6056,51 +6056,6 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* Chose the less restrictive of two < or <= comparisons.  */
-      if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Likewise chose the less restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LT_EXPR && code2 == GT_EXPR)
-		   || (code1 == GT_EXPR && code2 == LT_EXPR)))
-	return fold_build2 (NE_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for less/greater pairs that don't restrict the range at all.  */
-      else if (cmp >= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_true_node;
-      else if (cmp <= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_true_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
diff --git a/gcc/match.pd b/gcc/match.pd
index 0c706060055..29486ee8ec9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2063,6 +2063,45 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
        (if (code1 == NE_EXPR && !val) @3)))))))
 
+/* Convert (X OP1 CST1) || (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (for or (truth_or bit_ior)
+   (simplify
+   (or (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+     }
+     (switch
+      /* Choose the more restrictive of two < or <= comparisons.  */
+      (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+	@4
+	@3))
+      /* Likewise chose the more restrictive of two > or >= comparisons.  */
+      (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+	@4
+	@3))
+      /* Check for singleton ranges.  */
+      (if (cmp == 0
+	   && ((code1 == LT_EXPR && code2 == GT_EXPR)
+	       || (code1 == GT_EXPR && code2 == LT_EXPR)))
+       (ne @0 @2))
+      /* Check for disjoint ranges.  */
+      (if (cmp >= 0
+	   && (code1 == LT_EXPR || code1 == LE_EXPR)
+	   && (code2 == GT_EXPR || code2 == GE_EXPR))
+       { constant_boolean_node (true, type); })
+      (if (cmp <= 0
+	   && (code1 == GT_EXPR || code1 == GE_EXPR)
+	   && (code2 == LT_EXPR || code2 == LE_EXPR))
+       { constant_boolean_node (true, type); })
+      ))))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.
  2019-09-09 12:24                     ` [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd Martin Liška
@ 2019-09-11 11:19                       ` Martin Liška
  2019-09-11 13:57                         ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 11:19 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 197 bytes --]

Hi.

There's slightly updated version of the patch where
I use @3 and @4 in match.pd.

Patch can bootstrap on x86_64-linux-gnu and survives regression tests.

Ready to be installed?
Thanks,
Martin

[-- Attachment #2: 0004-Rewrite-first-part-of-or_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 4741 bytes --]

From 997ed7390bb2897cf880b29d14d0e28e5f8873c2 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:47:01 +0200
Subject: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules
	moved to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 87 +----------------------------------------------
 gcc/match.pd      | 29 ++++++++++++++++
 2 files changed, 30 insertions(+), 86 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 58235d613d3..5931cf3df0a 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6064,93 +6064,8 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
     {
       int cmp = tree_int_cst_compare (op1b, op2b);
 
-      /* If we have (op1a != op1b), we should either be able to
-	 return that or TRUE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	    }
-	}
-      /* Likewise if the second comparison is a != comparison.  */
-      else if (code2 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	    }
-	}
-
-      /* See if an equality test is redundant with the other comparison.  */
-      else if (code1 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
       /* Chose the less restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
+      if ((code1 == LT_EXPR || code1 == LE_EXPR)
 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
 	{
 	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
diff --git a/gcc/match.pd b/gcc/match.pd
index 008b93d906f..0c706060055 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2035,6 +2035,35 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        { constant_boolean_node (false, type); })
       ))))))
 
+/* Convert (X == CST1) || (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for or (truth_or bit_ior)
+   (simplify
+    (or:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+     (with
+      {
+       int cmp = tree_int_cst_compare (@1, @2);
+       bool val;
+       switch (code2)
+	 {
+	 case EQ_EXPR: val = (cmp == 0); break;
+	 case NE_EXPR: val = (cmp != 0); break;
+	 case LT_EXPR: val = (cmp < 0); break;
+	 case GT_EXPR: val = (cmp > 0); break;
+	 case LE_EXPR: val = (cmp <= 0); break;
+	 case GE_EXPR: val = (cmp >= 0); break;
+	 default: gcc_unreachable ();
+	 }
+      }
+      (switch
+       (if (code1 == EQ_EXPR && val) @4)
+       (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
+       (if (code1 == NE_EXPR && !val) @3)))))))
+
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-11 11:16                                   ` Martin Liška
@ 2019-09-11 12:23                                     ` Richard Biener
  2019-09-11 13:55                                       ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-11 12:23 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 665 bytes --]

On Wed, 11 Sep 2019, Martin Liška wrote:

> Hello.
> 
> One another updated version of the patch.
> Changes from the previous version:
> - I fixed:
>   gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
>   into gimple_size (GIMPLE_ASSIGN, 3)
> - I simplified condition in gimple_simplified_result_is_gimple_val
> - optimize_vec_cond_expr is using build_same_sized_truth_vector_type

Can you here instead amend ovce_extract_ops to return the type of
'cond' which should be the type you want?

Otherwise OK.

Richard.

> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?
> Thanks,
> Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-11 11:18                               ` Martin Liška
@ 2019-09-11 12:44                                 ` Richard Biener
  2019-09-11 13:19                                   ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-11 12:44 UTC (permalink / raw)
  To: Martin Liška
  Cc: gcc-patches, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 2556 bytes --]

On Wed, 11 Sep 2019, Martin Liška wrote:

> I'm sending updated version of the patch where I changed
> from previous version:
> - more compact matching is used (note @3 and @4):
>   (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?

--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,9 +1894,11 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
                          dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+       && s->match->location != s2->s->match->location)
       {

can you retain the warning for verbose >= 1 please?  And put in
a comment that duplicates are sometimes hard to avoid with
nested for so this keeps match.pd sources small.

+  /* Function maybe_fold_comparisons_from_match_pd creates temporary
+     SSA_NAMEs.  */
+  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
+    {
+      gimple *s = SSA_NAME_DEF_STMT (op2);
+      if (is_gimple_assign (s))
+       return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
+                                      gimple_assign_rhs1 (s),
+                                      gimple_assign_rhs2 (s));
+      else
+       return false;
+    }

when do you actually run into the need to add this?  The whole
same_bool_result_p/same_bool_comparison_p helpers look a bit
odd to me.  It shouldn't be special to the new temporaries
either so at least the comment looks out-of place.

+      else if (op.code.is_tree_code ()
+              && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+       {

COMPARISON_CLASS_P ((tree_code)op.code)

as was noted.

Any particular reason you needed to swap the calls in
maybe_fold_and/or_comparisons?

+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (for and (truth_and bit_and)
+   (simplify

You could save some code-bloat with writing

  (for and (
#if GENERIC
  truth_and
#endif
  bit_and)

but since you are moving the patterns from GIMPLE code I'd say
simply remove truth_and and that innermost for?

Otherwise OK.

Thanks,
Richard.




> Thanks,
> Martin
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 247165 (AG München)

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 2/2] Fix PR88784, middle end is missing some optimizations about unsigned
  2019-09-06 10:14                   ` [PATCH 2/2] Fix PR88784, middle " Martin Liška
@ 2019-09-11 13:08                     ` Richard Biener
  2019-09-11 13:56                       ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-11 13:08 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 3581 bytes --]

On Fri, 6 Sep 2019, Martin Liška wrote:

> On 9/5/19 3:17 PM, Richard Biener wrote:
> > On Tue, 16 Jul 2019, Li Jia He wrote:
> > 
> >> Hi,
> >>
> >>   I made some changes based on the recommendations. Would you like to
> >>   help me to see it again ? Sorry, it took so long time to provide the
> >>   patch.
> >>
> >>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
> >> 	The reason is that I did not found a good way to handle the
> >> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
> >> 	Maybe I missing some important information about match.pd.
> >> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
> >> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
> >> 	question with the value on the stack as the return value ?
> >> 	I may have misunderstood Richard's intention.
> > 
> > And now for the match.pd patch.
> > 
> > +/* x >  y  &&  x != XXX_MIN  -->  x > y  */
> > +(for and (truth_and bit_and)
> > + (simplify
> > +  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
> > +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
> > (TREE_TYPE(@1))
> > +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
> > +    @3)))
> > +
> > +/* x >  y  &&  x == XXX_MIN  -->  false  */
> > +(for and (truth_and bit_and)
> > + (simplify
> > +  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
> > +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
> > (TREE_TYPE(@1))
> > +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
> > +    { boolean_false_node; })))
> > 
> > you could merge those two via
> > 
> >  (for eqne (eq ne)
> >   (for and (....
> >    (simplify
> >     (and:c (gt:c @0 @1) (eqne @0 INTEGER_CST@2))
> >     (if (...)
> >      (switch
> >       (if (eqne == NE_EXPR)
> >        @3)
> >       (if (eqne == EQ_EXPR)
> >        { constant_boolean_node (false, type); }))))
> > 
> > notice using constant_boolean_node (false, type); instead of
> > boolean_false_node.  I suspect more unification is possible.
> > 
> > Also you could do
> > 
> > (match min_value
> >  INTEGER_CST
> >  (if (INTEGRAL_TYPE_P (type)
> >       && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
> > 
> > and then write
> > 
> >  (simplify
> >   (and:c (gt:c @0 @1) (eq @0 min_value))
> >   (...
> > 
> > Your
> > 
> > (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P
> > (TREE_TYPE(@1))
> > 
> > is redundant, it's enough to check either @0 or @1 given they
> > have to be compatible for the gt operation.  Note you probably
> > want to use
> > 
> >   (and:c (gt:c @0 @1) (eq @@0 min_value))
> > 
> > and verify that types_match (@1, @0) because when @0 are a constant
> > (and (eq @0 min_value) is not folded which can happen) then they
> > might have different types and thus you could have
> > (SHORT_MAX > intvar) && (SHORT_MAX == SHORT_MAX)
> > 
> > That said, the patterns can be quite a bit simplified I think.
> > 
> > Richard.
> > 
> 
> Likewise, I applied the suggested simplification.
> 
> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
> 
> Ready to be installed?

+/* { dg-options "-O2 -fdump-tree-ifcombine --param 
logical-op-non-short-circuit=0" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
...
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */

since you iterate over bit_and and truth_and GENERIC folding should
already simplify this, no?

I suggest to remove the truth_and/or iteration.

Otherwise looks OK now.

Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-11 12:44                                 ` Richard Biener
@ 2019-09-11 13:19                                   ` Martin Liška
  2019-09-11 13:57                                     ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:19 UTC (permalink / raw)
  To: Richard Biener
  Cc: gcc-patches, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/11/19 2:43 PM, Richard Biener wrote:
> On Wed, 11 Sep 2019, Martin Liška wrote:
> 
>> I'm sending updated version of the patch where I changed
>> from previous version:
>> - more compact matching is used (note @3 and @4):
>>   (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
> 
> --- a/gcc/genmatch.c
> +++ b/gcc/genmatch.c
> @@ -1894,9 +1894,11 @@ dt_node *
>  dt_node::append_simplify (simplify *s, unsigned pattern_no,
>                           dt_operand **indexes)
>  {
> +  dt_simplify *s2;
>    dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
>    for (unsigned i = 0; i < kids.length (); ++i)
> -    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
> +    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
> +       && s->match->location != s2->s->match->location)
>        {
> 
> can you retain the warning for verbose >= 1 please?  And put in
> a comment that duplicates are sometimes hard to avoid with
> nested for so this keeps match.pd sources small.

Sure.

> 
> +  /* Function maybe_fold_comparisons_from_match_pd creates temporary
> +     SSA_NAMEs.  */
> +  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
> +    {
> +      gimple *s = SSA_NAME_DEF_STMT (op2);
> +      if (is_gimple_assign (s))
> +       return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
> +                                      gimple_assign_rhs1 (s),
> +                                      gimple_assign_rhs2 (s));
> +      else
> +       return false;
> +    }
> 
> when do you actually run into the need to add this?  The whole
> same_bool_result_p/same_bool_comparison_p helpers look a bit
> odd to me.  It shouldn't be special to the new temporaries
> either so at least the comment looks out-of place.

At some point it was needed to handle gcc/testsuite/gcc.dg/pr46909.c
test-case. Apparently, now the test-case is fine with the hunk. I will it
removal of the hunk.

> 
> +      else if (op.code.is_tree_code ()
> +              && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
> +       {
> 
> COMPARISON_CLASS_P ((tree_code)op.code)
> 
> as was noted.

Won't work here:

/home/marxin/Programming/gcc/gcc/gimple-fold.c: In function ‘tree_node* maybe_fold_comparisons_from_match_pd(tree, tree_code, tree_code, tree, tree, tree_code, tree, tree)’:
/home/marxin/Programming/gcc/gcc/tree.h:239:49: error: base operand of ‘->’ is not a pointer
  239 | #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code)
      |                                                 ^~

> 
> Any particular reason you needed to swap the calls in
> maybe_fold_and/or_comparisons?
> 
> +(for code1 (eq ne)
> + (for code2 (eq ne lt gt le ge)
> +  (for and (truth_and bit_and)
> +   (simplify
> 
> You could save some code-bloat with writing
> 
>   (for and (
> #if GENERIC
>   truth_and
> #endif
>   bit_and)
> 
> but since you are moving the patterns from GIMPLE code I'd say
> simply remove truth_and and that innermost for?

I'm gonna drop the generic tree codes support.

Martin

> 
> Otherwise OK.
> 
> Thanks,
> Richard.
> 
> 
> 
> 
>> Thanks,
>> Martin
>>
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd
  2019-09-11 12:23                                     ` Richard Biener
@ 2019-09-11 13:55                                       ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:55 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 847 bytes --]

On 9/11/19 2:23 PM, Richard Biener wrote:
> On Wed, 11 Sep 2019, Martin Liška wrote:
> 
>> Hello.
>>
>> One another updated version of the patch.
>> Changes from the previous version:
>> - I fixed:
>>   gimple *stmt1 = (gimple *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 2));
>>   into gimple_size (GIMPLE_ASSIGN, 3)
>> - I simplified condition in gimple_simplified_result_is_gimple_val
>> - optimize_vec_cond_expr is using build_same_sized_truth_vector_type
> 
> Can you here instead amend ovce_extract_ops to return the type of
> 'cond' which should be the type you want?

Sure, updated in the tested attached patch.

I'm going to install the patch after the Cauldron.

Martin

> 
> Otherwise OK.
> 
> Richard.
> 
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
>> Thanks,
>> Martin


[-- Attachment #2: 0001-Auto-generate-maybe_fold_and-or_comparisons-from-mat.patch --]
[-- Type: text/x-patch, Size: 25706 bytes --]

From 8ad0d2e59350b9410543571059c0d24bcda52db3 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 00:30:25 -0500
Subject: [PATCH 1/5] Auto-generate maybe_fold_and/or_comparisons from match.pd

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (and_comparisons_1): Add type as first
	argument.
	(and_var_with_comparison): Likewise.
	(and_var_with_comparison_1): Likewise.
	(or_comparisons_1): Likewise.
	(or_var_with_comparison): Likewise.
	(or_var_with_comparison_1): Likewise.
	(maybe_fold_and_comparisons): Call maybe_fold_comparisons_from_match_pd.
	(maybe_fold_or_comparisons): Likewise.
	(maybe_fold_comparisons_from_match_pd): New.
	* gimple-fold.h (maybe_fold_and_comparisons): Add type argument.
	(maybe_fold_or_comparisons): Likewise.
	* gimple.c (gimple_size): Make it public and add num_ops argument.
	(gimple_init): New function.
	(gimple_alloc): Call gimple_init.
	* gimple.h (gimple_size): New.
	(gimple_init): Likewise.
	* tree-if-conv.c (fold_or_predicates): Pass type.
	* tree-ssa-ifcombine.c (ifcombine_ifandif): Likewise.
	* tree-ssa-reassoc.c (eliminate_redundant_comparison): Likewise.
	(optimize_vec_cond_expr): Likewise.
	(ovce_extract_ops): Return type of conditional expression.
	* tree-ssanames.c (init_ssa_name_imm_use): New.
	(make_ssa_name_fn): Use init_ssa_name_imm_use.
	* tree-ssanames.h (init_ssa_name_imm_use): New.
---
 gcc/gimple-fold.c        | 170 +++++++++++++++++++++++++++++----------
 gcc/gimple-fold.h        |   4 +-
 gcc/gimple.c             |  37 +++++----
 gcc/gimple.h             |   2 +
 gcc/tree-if-conv.c       |   2 +-
 gcc/tree-ssa-ifcombine.c |   2 +-
 gcc/tree-ssa-reassoc.c   |  25 ++++--
 gcc/tree-ssanames.c      |  21 +++--
 gcc/tree-ssanames.h      |   1 +
 9 files changed, 189 insertions(+), 75 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index fcffb9802b7..6d9ba367839 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5371,22 +5371,22 @@ same_bool_result_p (const_tree op1, const_tree op2)
 /* Forward declarations for some mutually recursive functions.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b);
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b);
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b);
 
 /* Helper function for and_comparisons_1:  try to simplify the AND of the
@@ -5395,7 +5395,7 @@ or_var_with_comparison_1 (gimple *stmt,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison (tree var, bool invert,
+and_var_with_comparison (tree type, tree var, bool invert,
 			 enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5409,11 +5409,11 @@ and_var_with_comparison (tree var, bool invert,
      !var AND (op2a code2 op2b) => !(var OR !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = or_var_with_comparison_1 (stmt, 
+    t = or_var_with_comparison_1 (type, stmt,
 				  invert_tree_comparison (code2, false),
 				  op2a, op2b);
   else
-    t = and_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = and_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5422,7 +5422,7 @@ and_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-and_var_with_comparison_1 (gimple *stmt,
+and_var_with_comparison_1 (tree type, gimple *stmt,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5453,7 +5453,7 @@ and_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = and_comparisons_1 (innercode,
+      tree t = and_comparisons_1 (type, innercode,
 				  gimple_assign_rhs1 (stmt),
 				  gimple_assign_rhs2 (stmt),
 				  code2,
@@ -5489,18 +5489,20 @@ and_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner2, false, code2, op2a,
+					   op2b));
       else if (inner2 == false_test_var)
 	return (is_and
 		? boolean_false_node
-		: and_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: and_var_with_comparison (type, inner1, false, code2, op2a,
+					   op2b));
 
       /* Next, redistribute/reassociate the AND across the inner tests.
 	 Compute the first partial result, (inner1 AND (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5532,7 +5534,7 @@ and_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_and_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_and_comparisons (type, gimple_assign_rhs_code (s),
 					      gimple_assign_rhs1 (s),
 					      gimple_assign_rhs2 (s),
 					      code2, op2a, op2b)))
@@ -5588,7 +5590,7 @@ and_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		   enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -5762,7 +5764,8 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return and_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return and_var_with_comparison (type, op1a, invert, code2, op2a,
+					  op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -5812,7 +5815,7 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = and_var_with_comparison (arg, invert, code2,
+		      temp = and_var_with_comparison (type, arg, invert, code2,
 						      op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -5834,6 +5837,73 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
   return NULL_TREE;
 }
 
+/* Helper function for maybe_fold_and_comparisons and maybe_fold_or_comparisons
+   : try to simplify the AND/OR of the ssa variable VAR with the comparison
+   specified by (OP2A CODE2 OP2B) from match.pd.  Return NULL_EXPR if we can't
+   simplify this to a single expression.  As we are going to lower the cost
+   of building SSA names / gimple stmts significantly, we need to allocate
+   them ont the stack.  This will cause the code to be a bit ugly.  */
+
+static tree
+maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
+				      enum tree_code code1,
+				      tree op1a, tree op1b,
+				      enum tree_code code2, tree op2a,
+				      tree op2b)
+{
+  /* Allocate gimple stmt1 on the stack.  */
+  gassign *stmt1
+    = (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+  gimple_init (stmt1, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt1, code1);
+  gimple_assign_set_rhs1 (stmt1, op1a);
+  gimple_assign_set_rhs2 (stmt1, op1b);
+
+  /* Allocate gimple stmt2 on the stack.  */
+  gassign *stmt2
+    = (gassign *) XALLOCAVEC (char, gimple_size (GIMPLE_ASSIGN, 3));
+  gimple_init (stmt2, GIMPLE_ASSIGN, 3);
+  gimple_assign_set_rhs_code (stmt2, code2);
+  gimple_assign_set_rhs1 (stmt2, op2a);
+  gimple_assign_set_rhs2 (stmt2, op2b);
+
+  /* Allocate SSA names(lhs1) on the stack.  */
+  tree lhs1 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs1, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs1, SSA_NAME);
+  TREE_TYPE (lhs1) = type;
+  init_ssa_name_imm_use (lhs1);
+
+  /* Allocate SSA names(lhs2) on the stack.  */
+  tree lhs2 = (tree)XALLOCA (tree_ssa_name);
+  memset (lhs2, 0, sizeof (tree_ssa_name));
+  TREE_SET_CODE (lhs2, SSA_NAME);
+  TREE_TYPE (lhs2) = type;
+  init_ssa_name_imm_use (lhs2);
+
+  gimple_assign_set_lhs (stmt1, lhs1);
+  gimple_assign_set_lhs (stmt2, lhs2);
+
+  gimple_match_op op (gimple_match_cond::UNCOND, code,
+		      type, gimple_assign_lhs (stmt1),
+		      gimple_assign_lhs (stmt2));
+  if (op.resimplify (NULL, follow_all_ssa_edges))
+    {
+      if (gimple_simplified_result_is_gimple_val (&op))
+	{
+	  tree res = op.ops[0];
+	  if (res == lhs1)
+	    return build2 (code1, type, op1a, op1b);
+	  else if (res == lhs2)
+	    return build2 (code2, type, op2a, op2b);
+	  else
+	    return res;
+	}
+    }
+
+  return NULL_TREE;
+}
+
 /* Try to simplify the AND of two comparisons, specified by
    (OP1A CODE1 OP1B) and (OP2B CODE2 OP2B), respectively.
    If this can be simplified to a single expression (without requiring
@@ -5842,14 +5912,22 @@ and_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_and_comparisons (tree type,
+			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = and_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return and_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
 }
 
 /* Helper function for or_comparisons_1:  try to simplify the OR of the
@@ -5858,7 +5936,7 @@ maybe_fold_and_comparisons (enum tree_code code1, tree op1a, tree op1b,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison (tree var, bool invert,
+or_var_with_comparison (tree type, tree var, bool invert,
 			enum tree_code code2, tree op2a, tree op2b)
 {
   tree t;
@@ -5872,11 +5950,11 @@ or_var_with_comparison (tree var, bool invert,
      !var OR (op2a code2 op2b) => !(var AND !(op2a code2 op2b))
      Then we only have to consider the simpler non-inverted cases.  */
   if (invert)
-    t = and_var_with_comparison_1 (stmt, 
+    t = and_var_with_comparison_1 (type, stmt,
 				   invert_tree_comparison (code2, false),
 				   op2a, op2b);
   else
-    t = or_var_with_comparison_1 (stmt, code2, op2a, op2b);
+    t = or_var_with_comparison_1 (type, stmt, code2, op2a, op2b);
   return canonicalize_bool (t, invert);
 }
 
@@ -5885,7 +5963,7 @@ or_var_with_comparison (tree var, bool invert,
    Return NULL_EXPR if we can't simplify this to a single expression.  */
 
 static tree
-or_var_with_comparison_1 (gimple *stmt,
+or_var_with_comparison_1 (tree type, gimple *stmt,
 			  enum tree_code code2, tree op2a, tree op2b)
 {
   tree var = gimple_assign_lhs (stmt);
@@ -5916,7 +5994,7 @@ or_var_with_comparison_1 (gimple *stmt,
   /* If the definition is a comparison, recurse on it.  */
   if (TREE_CODE_CLASS (innercode) == tcc_comparison)
     {
-      tree t = or_comparisons_1 (innercode,
+      tree t = or_comparisons_1 (type, innercode,
 				 gimple_assign_rhs1 (stmt),
 				 gimple_assign_rhs2 (stmt),
 				 code2,
@@ -5952,18 +6030,20 @@ or_var_with_comparison_1 (gimple *stmt,
       else if (inner1 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner2, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner2, false, code2, op2a,
+					  op2b));
       else if (inner2 == false_test_var)
 	return (is_or
 		? boolean_true_node
-		: or_var_with_comparison (inner1, false, code2, op2a, op2b));
+		: or_var_with_comparison (type, inner1, false, code2, op2a,
+					  op2b));
       
       /* Next, redistribute/reassociate the OR across the inner tests.
 	 Compute the first partial result, (inner1 OR (op2a code op2b))  */
       if (TREE_CODE (inner1) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner1))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -5995,7 +6075,7 @@ or_var_with_comparison_1 (gimple *stmt,
       if (TREE_CODE (inner2) == SSA_NAME
 	  && is_gimple_assign (s = SSA_NAME_DEF_STMT (inner2))
 	  && TREE_CODE_CLASS (gimple_assign_rhs_code (s)) == tcc_comparison
-	  && (t = maybe_fold_or_comparisons (gimple_assign_rhs_code (s),
+	  && (t = maybe_fold_or_comparisons (type, gimple_assign_rhs_code (s),
 					     gimple_assign_rhs1 (s),
 					     gimple_assign_rhs2 (s),
 					     code2, op2a, op2b)))
@@ -6052,7 +6132,7 @@ or_var_with_comparison_1 (gimple *stmt,
    in the first comparison but not the second.  */
 
 static tree
-or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
+or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 		  enum tree_code code2, tree op2a, tree op2b)
 {
   tree truth_type = truth_type_for (TREE_TYPE (op1a));
@@ -6226,7 +6306,8 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 	{
 	case GIMPLE_ASSIGN:
 	  /* Try to simplify by copy-propagating the definition.  */
-	  return or_var_with_comparison (op1a, invert, code2, op2a, op2b);
+	  return or_var_with_comparison (type, op1a, invert, code2, op2a,
+					 op2b);
 
 	case GIMPLE_PHI:
 	  /* If every argument to the PHI produces the same result when
@@ -6276,7 +6357,7 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
 					     gimple_bb (def_stmt),
 					     gimple_bb (stmt)))
 			return NULL_TREE;
-		      temp = or_var_with_comparison (arg, invert, code2,
+		      temp = or_var_with_comparison (type, arg, invert, code2,
 						     op2a, op2b);
 		      if (!temp)
 			return NULL_TREE;
@@ -6306,16 +6387,23 @@ or_comparisons_1 (enum tree_code code1, tree op1a, tree op1b,
    If the result expression is non-null, it has boolean type.  */
 
 tree
-maybe_fold_or_comparisons (enum tree_code code1, tree op1a, tree op1b,
+maybe_fold_or_comparisons (tree type,
+			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  tree t = or_comparisons_1 (code1, op1a, op1b, code2, op2a, op2b);
-  if (t)
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
-  else
-    return or_comparisons_1 (code2, op2a, op2b, code1, op1a, op1b);
-}
 
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
+    return t;
+
+  return NULL_TREE;
+}
 
 /* Fold STMT to a constant using VALUEIZE to valueize SSA names.
 
diff --git a/gcc/gimple-fold.h b/gcc/gimple-fold.h
index 673d484ff52..f9d1d54daf4 100644
--- a/gcc/gimple-fold.h
+++ b/gcc/gimple-fold.h
@@ -31,9 +31,9 @@ extern void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 extern bool fold_stmt (gimple_stmt_iterator *);
 extern bool fold_stmt (gimple_stmt_iterator *, tree (*) (tree));
 extern bool fold_stmt_inplace (gimple_stmt_iterator *);
-extern tree maybe_fold_and_comparisons (enum tree_code, tree, tree, 
+extern tree maybe_fold_and_comparisons (tree, enum tree_code, tree, tree,
 					enum tree_code, tree, tree);
-extern tree maybe_fold_or_comparisons (enum tree_code, tree, tree,
+extern tree maybe_fold_or_comparisons (tree, enum tree_code, tree, tree,
 				       enum tree_code, tree, tree);
 extern bool optimize_atomic_compare_exchange_p (gimple *);
 extern void fold_builtin_atomic_compare_exchange (gimple_stmt_iterator *);
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 633ef512a19..88250cad16b 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -110,10 +110,27 @@ gimple_set_code (gimple *g, enum gimple_code code)
 /* Return the number of bytes needed to hold a GIMPLE statement with
    code CODE.  */
 
-static inline size_t
-gimple_size (enum gimple_code code)
+size_t
+gimple_size (enum gimple_code code, unsigned num_ops)
 {
-  return gsstruct_code_size[gss_for_code (code)];
+  size_t size = gsstruct_code_size[gss_for_code (code)];
+  if (num_ops > 0)
+    size += (sizeof (tree) * (num_ops - 1));
+  return size;
+}
+
+/* Initialize GIMPLE statement G with CODE and NUM_OPS.  */
+
+void
+gimple_init (gimple *g, enum gimple_code code, unsigned num_ops)
+{
+  gimple_set_code (g, code);
+  gimple_set_num_ops (g, num_ops);
+
+  /* Do not call gimple_set_modified here as it has other side
+     effects and this tuple is still not completely built.  */
+  g->modified = 1;
+  gimple_init_singleton (g);
 }
 
 /* Allocate memory for a GIMPLE statement with code CODE and NUM_OPS
@@ -125,10 +142,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
   size_t size;
   gimple *stmt;
 
-  size = gimple_size (code);
-  if (num_ops > 0)
-    size += sizeof (tree) * (num_ops - 1);
-
+  size = gimple_size (code, num_ops);
   if (GATHER_STATISTICS)
     {
       enum gimple_alloc_kind kind = gimple_alloc_kind (code);
@@ -137,14 +151,7 @@ gimple_alloc (enum gimple_code code, unsigned num_ops MEM_STAT_DECL)
     }
 
   stmt = ggc_alloc_cleared_gimple_statement_stat (size PASS_MEM_STAT);
-  gimple_set_code (stmt, code);
-  gimple_set_num_ops (stmt, num_ops);
-
-  /* Do not call gimple_set_modified here as it has other side
-     effects and this tuple is still not completely built.  */
-  stmt->modified = 1;
-  gimple_init_singleton (stmt);
-
+  gimple_init (stmt, code, num_ops);
   return stmt;
 }
 
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 55f5d0d33d9..cf1f8da5ae2 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -1445,6 +1445,8 @@ extern enum gimple_statement_structure_enum const gss_for_code_[];
    of comminucating the profile info to the builtin expanders.  */
 extern gimple *currently_expanding_gimple_stmt;
 
+size_t gimple_size (enum gimple_code code, unsigned num_ops = 0);
+void gimple_init (gimple *g, enum gimple_code code, unsigned num_ops);
 gimple *gimple_alloc (enum gimple_code, unsigned CXX_MEM_STAT_INFO);
 greturn *gimple_build_return (tree);
 void gimple_call_reset_alias_info (gcall *);
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index da67e39e03a..40ad4c5947a 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -436,7 +436,7 @@ fold_or_predicates (location_t loc, tree c1, tree c2)
 
   if (code1 != ERROR_MARK && code2 != ERROR_MARK)
     {
-      tree t = maybe_fold_or_comparisons (code1, op1a, op1b,
+      tree t = maybe_fold_or_comparisons (boolean_type_node, code1, op1a, op1b,
 					  code2, op2a, op2b);
       if (t)
 	return t;
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index f30816ace7b..90d8bb5e9e7 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -555,7 +555,7 @@ ifcombine_ifandif (basic_block inner_cond_bb, bool inner_inv,
 	return false;
       /* Don't return false so fast, try maybe_fold_or_comparisons?  */
 
-      if (!(t = maybe_fold_and_comparisons (inner_cond_code,
+      if (!(t = maybe_fold_and_comparisons (boolean_type_node, inner_cond_code,
 					    gimple_cond_lhs (inner_cond),
 					    gimple_cond_rhs (inner_cond),
 					    outer_cond_code,
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index df76e66bccf..510dfd1e188 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -2088,12 +2088,15 @@ eliminate_redundant_comparison (enum tree_code opcode,
 
       /* If we got here, we have a match.  See if we can combine the
 	 two comparisons.  */
+      tree type = TREE_TYPE (gimple_assign_lhs (def1));
       if (opcode == BIT_IOR_EXPR)
-	t = maybe_fold_or_comparisons (lcode, op1, op2,
+	t = maybe_fold_or_comparisons (type,
+				       lcode, op1, op2,
 				       rcode, gimple_assign_rhs1 (def2),
 				       gimple_assign_rhs2 (def2));
       else
-	t = maybe_fold_and_comparisons (lcode, op1, op2,
+	t = maybe_fold_and_comparisons (type,
+					lcode, op1, op2,
 					rcode, gimple_assign_rhs1 (def2),
 					gimple_assign_rhs2 (def2));
       if (!t)
@@ -3745,10 +3748,11 @@ optimize_range_tests (enum tree_code opcode,
 
 /* A subroutine of optimize_vec_cond_expr to extract and canonicalize
    the operands of the VEC_COND_EXPR.  Returns ERROR_MARK on failure,
-   otherwise the comparison code.  */
+   otherwise the comparison code.  TYPE is a return value that is set
+   to type of comparison.  */
 
 static tree_code
-ovce_extract_ops (tree var, gassign **rets, bool *reti)
+ovce_extract_ops (tree var, gassign **rets, bool *reti, tree *type)
 {
   if (TREE_CODE (var) != SSA_NAME)
     return ERROR_MARK;
@@ -3790,6 +3794,8 @@ ovce_extract_ops (tree var, gassign **rets, bool *reti)
     *rets = stmt;
   if (reti)
     *reti = inv;
+  if (type)
+    *type = TREE_TYPE (cond);
   return cmp;
 }
 
@@ -3811,7 +3817,8 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 
       gassign *stmt0;
       bool invert;
-      tree_code cmp0 = ovce_extract_ops (elt0, &stmt0, &invert);
+      tree type;
+      tree_code cmp0 = ovce_extract_ops (elt0, &stmt0, &invert, &type);
       if (cmp0 == ERROR_MARK)
 	continue;
 
@@ -3820,7 +3827,7 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 	  tree &elt1 = (*ops)[j]->op;
 
 	  gassign *stmt1;
-	  tree_code cmp1 = ovce_extract_ops (elt1, &stmt1, NULL);
+	  tree_code cmp1 = ovce_extract_ops (elt1, &stmt1, NULL, NULL);
 	  if (cmp1 == ERROR_MARK)
 	    continue;
 
@@ -3834,9 +3841,11 @@ optimize_vec_cond_expr (tree_code opcode, vec<operand_entry *> *ops)
 
 	  tree comb;
 	  if (opcode == BIT_AND_EXPR)
-	    comb = maybe_fold_and_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_and_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					       y1);
 	  else if (opcode == BIT_IOR_EXPR)
-	    comb = maybe_fold_or_comparisons (cmp0, x0, y0, cmp1, x1, y1);
+	    comb = maybe_fold_or_comparisons (type, cmp0, x0, y0, cmp1, x1,
+					      y1);
 	  else
 	    gcc_unreachable ();
 	  if (comb == NULL)
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 3911db9c26e..f7b638dba11 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -252,6 +252,19 @@ flush_ssaname_freelist (void)
   vec_safe_truncate (FREE_SSANAMES_QUEUE (cfun), 0);
 }
 
+/* Initialize SSA_NAME_IMM_USE_NODE of a SSA NAME.  */
+
+void
+init_ssa_name_imm_use (tree name)
+{
+  use_operand_p imm;
+  imm = &(SSA_NAME_IMM_USE_NODE (name));
+  imm->use = NULL;
+  imm->prev = imm;
+  imm->next = imm;
+  imm->loc.ssa_name = name;
+}
+
 /* Return an SSA_NAME node for variable VAR defined in statement STMT
    in function FN.  STMT may be an empty statement for artificial
    references (e.g., default definitions created when a variable is
@@ -263,8 +276,6 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 		  unsigned int version)
 {
   tree t;
-  use_operand_p imm;
-
   gcc_assert (VAR_P (var)
 	      || TREE_CODE (var) == PARM_DECL
 	      || TREE_CODE (var) == RESULT_DECL
@@ -318,11 +329,7 @@ make_ssa_name_fn (struct function *fn, tree var, gimple *stmt,
 
   SSA_NAME_IN_FREE_LIST (t) = 0;
   SSA_NAME_IS_DEFAULT_DEF (t) = 0;
-  imm = &(SSA_NAME_IMM_USE_NODE (t));
-  imm->use = NULL;
-  imm->prev = imm;
-  imm->next = imm;
-  imm->loc.ssa_name = t;
+  init_ssa_name_imm_use (t);
 
   return t;
 }
diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h
index 6e6cffbce6a..1a7d0bccdf8 100644
--- a/gcc/tree-ssanames.h
+++ b/gcc/tree-ssanames.h
@@ -82,6 +82,7 @@ extern void fini_ssanames (struct function *);
 extern void ssanames_print_statistics (void);
 extern tree make_ssa_name_fn (struct function *, tree, gimple *,
 			      unsigned int version = 0);
+extern void init_ssa_name_imm_use (tree);
 extern void release_ssa_name_fn (struct function *, tree);
 extern bool get_ptr_info_alignment (struct ptr_info_def *, unsigned int *,
 				    unsigned int *);
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 2/2] Fix PR88784, middle end is missing some optimizations about unsigned
  2019-09-11 13:08                     ` Richard Biener
@ 2019-09-11 13:56                       ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:56 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 3695 bytes --]

On 9/11/19 3:08 PM, Richard Biener wrote:
> On Fri, 6 Sep 2019, Martin Liška wrote:
> 
>> On 9/5/19 3:17 PM, Richard Biener wrote:
>>> On Tue, 16 Jul 2019, Li Jia He wrote:
>>>
>>>> Hi,
>>>>
>>>>   I made some changes based on the recommendations. Would you like to
>>>>   help me to see it again ? Sorry, it took so long time to provide the
>>>>   patch.
>>>>
>>>>   Note: 1. I keep the code for and_comparisons_1 and or_comparisons_1.
>>>> 	The reason is that I did not found a good way to handle the
>>>> 	optimization of '((x CODE1 y) AND (x CODE2 y))' in match.pd.
>>>> 	Maybe I missing some important information about match.pd.
>>>> 	2. The gimple_resimplify2 function is not used.  Since stmt1,
>>>> 	stmt2, lhs1 and lhs2 are allocated on the stack, Is there a
>>>> 	question with the value on the stack as the return value ?
>>>> 	I may have misunderstood Richard's intention.
>>>
>>> And now for the match.pd patch.
>>>
>>> +/* x >  y  &&  x != XXX_MIN  -->  x > y  */
>>> +(for and (truth_and bit_and)
>>> + (simplify
>>> +  (and:c (gt:c@3 @0 @1) (ne @0 INTEGER_CST@2))
>>> +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
>>> (TREE_TYPE(@1))
>>> +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
>>> +    @3)))
>>> +
>>> +/* x >  y  &&  x == XXX_MIN  -->  false  */
>>> +(for and (truth_and bit_and)
>>> + (simplify
>>> +  (and:c (gt:c @0 @1) (eq @0 INTEGER_CST@2))
>>> +  (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P 
>>> (TREE_TYPE(@1))
>>> +       && (wi::eq_p (wi::to_wide (@2), wi::min_value (TREE_TYPE (@2)))))
>>> +    { boolean_false_node; })))
>>>
>>> you could merge those two via
>>>
>>>  (for eqne (eq ne)
>>>   (for and (....
>>>    (simplify
>>>     (and:c (gt:c @0 @1) (eqne @0 INTEGER_CST@2))
>>>     (if (...)
>>>      (switch
>>>       (if (eqne == NE_EXPR)
>>>        @3)
>>>       (if (eqne == EQ_EXPR)
>>>        { constant_boolean_node (false, type); }))))
>>>
>>> notice using constant_boolean_node (false, type); instead of
>>> boolean_false_node.  I suspect more unification is possible.
>>>
>>> Also you could do
>>>
>>> (match min_value
>>>  INTEGER_CST
>>>  (if (INTEGRAL_TYPE_P (type)
>>>       && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
>>>
>>> and then write
>>>
>>>  (simplify
>>>   (and:c (gt:c @0 @1) (eq @0 min_value))
>>>   (...
>>>
>>> Your
>>>
>>> (if (INTEGRAL_TYPE_P (TREE_TYPE (@0)) && INTEGRAL_TYPE_P
>>> (TREE_TYPE(@1))
>>>
>>> is redundant, it's enough to check either @0 or @1 given they
>>> have to be compatible for the gt operation.  Note you probably
>>> want to use
>>>
>>>   (and:c (gt:c @0 @1) (eq @@0 min_value))
>>>
>>> and verify that types_match (@1, @0) because when @0 are a constant
>>> (and (eq @0 min_value) is not folded which can happen) then they
>>> might have different types and thus you could have
>>> (SHORT_MAX > intvar) && (SHORT_MAX == SHORT_MAX)
>>>
>>> That said, the patterns can be quite a bit simplified I think.
>>>
>>> Richard.
>>>
>>
>> Likewise, I applied the suggested simplification.
>>
>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>
>> Ready to be installed?
> 
> +/* { dg-options "-O2 -fdump-tree-ifcombine --param 
> logical-op-non-short-circuit=0" } */
> +
> +#include <limits.h>
> +
> +_Bool and1(unsigned x, unsigned y)
> +{
> +  /* x > y && x != 0 --> x > y */
> +  return x > y && x != 0;
> +}
> ...
> +/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
> 
> since you iterate over bit_and and truth_and GENERIC folding should
> already simplify this, no?
> 
> I suggest to remove the truth_and/or iteration.

Done in updated patch.

Martin

> 
> Otherwise looks OK now.
> 
> Richard.
> 


[-- Attachment #2: 0002-Fix-PR88784-middle-end-is-missing-some-optimizations.patch --]
[-- Type: text/x-patch, Size: 18329 bytes --]

From acb5e62c2babf749b60c5475925ac6afb059e459 Mon Sep 17 00:00:00 2001
From: Li Jia He <helijia@linux.ibm.com>
Date: Mon, 15 Jul 2019 03:50:34 -0500
Subject: [PATCH 2/5] Fix PR88784, middle end is missing some optimizations
 about unsigned

Hi,

According to the optimizable case described by Qi Feng on
issue 88784, we can combine the cases into the following:

1. x >  y  &&  x != XXX_MIN  -->   x > y
2. x >  y  &&  x == XXX_MIN  -->   false
3. x <= y  &&  x == XXX_MIN  -->   x == XXX_MIN

4. x <  y  &&  x != XXX_MAX  -->   x < y
5. x <  y  &&  x == XXX_MAX  -->   false
6. x >= y  &&  x == XXX_MAX  -->   x == XXX_MAX

7. x >  y  ||  x != XXX_MIN  -->   x != XXX_MIN
8. x <= y  ||  x != XXX_MIN  -->   true
9. x <= y  ||  x == XXX_MIN  -->   x <= y

10. x <  y  ||  x != XXX_MAX  -->   x != UXXX_MAX
11. x >= y  ||  x != XXX_MAX  -->   true
12. x >= y  ||  x == XXX_MAX  -->   x >= y

Note: XXX_MIN represents the minimum value of type x.
      XXX_MAX represents the maximum value of type x.

Here we don't need to care about whether the operation is
signed or unsigned.  For example, in the below equation:

'x >  y  &&  x != XXX_MIN  -->   x > y'

If the x type is signed int and XXX_MIN is INT_MIN, we can
optimize it to 'x > y'.  However, if the type of x is unsigned
int and XXX_MIN is 0, we can still optimize it to 'x > y'.

The regression testing for the patch was done on GCC mainline on

    powerpc64le-unknown-linux-gnu (Power 9 LE)

with no regressions.  Is it OK for trunk ?

Thanks,
Lijia He

gcc/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* match.pd (x >  y  &&  x != XXX_MIN): Optimize into 'x > y'.
	(x >  y  &&  x == XXX_MIN): Optimize into 'false'.
	(x <= y  &&  x == XXX_MIN): Optimize into 'x == XXX_MIN'.
	(x <  y  &&  x != XXX_MAX): Optimize into 'x < y'.
	(x <  y  &&  x == XXX_MAX): Optimize into 'false'.
	(x >= y  &&  x == XXX_MAX): Optimize into 'x == XXX_MAX'.
	(x >  y  ||  x != XXX_MIN): Optimize into 'x != XXX_MIN'.
	(x <= y  ||  x != XXX_MIN): Optimize into 'true'.
	(x <= y  ||  x == XXX_MIN): Optimize into 'x <= y'.
	(x <  y  ||  x != XXX_MAX): Optimize into 'x != XXX_MAX'.
	(x >= y  ||  x != XXX_MAX): Optimize into 'true'.
	(x >= y  ||  x == XXX_MAX): Optimize into 'x >= y'.

gcc/testsuite/ChangeLog

2019-07-16  Li Jia He  <helijia@linux.ibm.com>
	    Qi Feng  <ffengqi@linux.ibm.com>

	PR middle-end/88784
	* gcc.dg/pr88784-1.c: New testcase.
	* gcc.dg/pr88784-2.c: New testcase.
	* gcc.dg/pr88784-3.c: New testcase.
	* gcc.dg/pr88784-4.c: New testcase.
	* gcc.dg/pr88784-5.c: New testcase.
	* gcc.dg/pr88784-6.c: New testcase.
	* gcc.dg/pr88784-7.c: New testcase.
	* gcc.dg/pr88784-8.c: New testcase.
	* gcc.dg/pr88784-9.c: New testcase.
	* gcc.dg/pr88784-10.c: New testcase.
	* gcc.dg/pr88784-11.c: New testcase.
	* gcc.dg/pr88784-12.c: New testcase.
---
 gcc/match.pd                      | 82 +++++++++++++++++++++++++++++--
 gcc/testsuite/gcc.dg/pr88784-1.c  | 30 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-10.c | 32 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-11.c | 30 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-12.c | 30 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-2.c  | 30 +++++++++++
 gcc/testsuite/gcc.dg/pr88784-3.c  | 32 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-4.c  | 32 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-5.c  | 31 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-6.c  | 31 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-7.c  | 31 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-8.c  | 31 ++++++++++++
 gcc/testsuite/gcc.dg/pr88784-9.c  | 32 ++++++++++++
 13 files changed, 450 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-10.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-11.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-12.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-3.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-4.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-5.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-6.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-7.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-8.c
 create mode 100644 gcc/testsuite/gcc.dg/pr88784-9.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 5690cf3d349..2ca88000cad 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1883,6 +1883,80 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     { wide_int_to_tree (type, (wi::to_wide (@1)
 			       & (bitpos / BITS_PER_UNIT))); }))))
 
+(match min_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::min_value (type)))))
+
+(match max_value
+ INTEGER_CST
+ (if (INTEGRAL_TYPE_P (type)
+      && wi::eq_p (wi::to_wide (t), wi::max_value (type)))))
+
+/* x >  y  &&  x != XXX_MIN  -->  x > y
+   x >  y  &&  x == XXX_MIN  -->  false . */
+(for eqne (eq ne)
+ (simplify
+  (bit_and:c (gt:c@2 @0 @1) (eqne @0 min_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     { constant_boolean_node (false, type); })
+    (if (eqne == NE_EXPR)
+     @2)
+    )))
+
+/* x <  y  &&  x != XXX_MAX  -->  x < y
+   x <  y  &&  x == XXX_MAX  -->  false.  */
+(for eqne (eq ne)
+ (simplify
+  (bit_and:c (lt:c@2 @0 @1) (eqne @0 max_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     { constant_boolean_node (false, type); })
+    (if (eqne == NE_EXPR)
+     @2)
+    )))
+
+/* x <=  y  &&  x == XXX_MIN  -->  x == XXX_MIN.  */
+(simplify
+ (bit_and:c (le:c @0 @1) (eq@2 @0 min_value))
+  @2)
+
+/* x >=  y  &&  x == XXX_MAX  -->  x == XXX_MAX.  */
+(simplify
+ (bit_and:c (ge:c @0 @1) (eq@2 @0 max_value))
+  @2)
+
+/* x >  y  ||  x != XXX_MIN   -->  x != XXX_MIN.  */
+(simplify
+ (bit_ior:c (gt:c @0 @1) (ne@2 @0 min_value))
+  @2)
+
+/* x <=  y  ||  x != XXX_MIN   -->  true.  */
+(simplify
+ (bit_ior:c (le:c @0 @1) (ne @0 min_value))
+  { constant_boolean_node (true, type); })
+
+/* x <=  y  ||  x == XXX_MIN   -->  x <= y.  */
+(simplify
+ (bit_ior:c (le:c@2 @0 @1) (eq @0 min_value))
+  @2)
+
+/* x <  y  ||  x != XXX_MAX   -->  x != XXX_MAX.  */
+(simplify
+ (bit_ior:c (lt:c @0 @1) (ne@2 @0 max_value))
+  @2)
+
+/* x >=  y  ||  x != XXX_MAX   -->  true
+   x >=  y  ||  x == XXX_MAX   -->  x >= y.  */
+(for eqne (eq ne)
+ (simplify
+  (bit_ior:c (ge:c@2 @0 @1) (eqne @0 max_value))
+   (switch
+    (if (eqne == EQ_EXPR)
+     @2)
+    (if (eqne == NE_EXPR)
+     { constant_boolean_node (true, type); }))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
@@ -5425,10 +5499,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
    on c, so could drop potentially-trapping arithmetic, but that's a valid
    simplification if the result of the operation isn't needed.
 
-   Avoid speculatively generating a stand-alone vector comparison                                                                                
-   on targets that might not support them.  Any target implementing                                                                              
-   conditional internal functions must support the same comparisons                                                                              
-   inside and outside a VEC_COND_EXPR.  */                                                                                                       
+   Avoid speculatively generating a stand-alone vector comparison
+   on targets that might not support them.  Any target implementing
+   conditional internal functions must support the same comparisons
+   inside and outside a VEC_COND_EXPR.  */
 
 #if GIMPLE
 (for uncond_op (UNCOND_BINARY)
diff --git a/gcc/testsuite/gcc.dg/pr88784-1.c b/gcc/testsuite/gcc.dg/pr88784-1.c
new file mode 100644
index 00000000000..b8daae0b330
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-10.c b/gcc/testsuite/gcc.dg/pr88784-10.c
new file mode 100644
index 00000000000..958d7656556
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-10.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-11.c b/gcc/testsuite/gcc.dg/pr88784-11.c
new file mode 100644
index 00000000000..c4b05082443
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-11.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-12.c b/gcc/testsuite/gcc.dg/pr88784-12.c
new file mode 100644
index 00000000000..5b60b3883f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-12.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dce3" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x == 0 --> x <= y */
+  return x <= y || x == 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x == UINT_MAX --> x >= y */
+  return x >= y || x == UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x == INT_MIN --> x <= y */
+  return x <= y || x == INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x == INT_MAX --> x >= y */
+  return x >= y || x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "dce3" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-2.c b/gcc/testsuite/gcc.dg/pr88784-2.c
new file mode 100644
index 00000000000..ed360018b0f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x != 0 --> x > y */
+  return x > y && x != 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x != UINT_MAX --> x < y */
+  return x < y && x != UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x != INT_MIN --> x > y */
+  return x > y && x != INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x != INT_MAX --> x < y */
+  return x < y && x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-3.c b/gcc/testsuite/gcc.dg/pr88784-3.c
new file mode 100644
index 00000000000..8c48e1b8943
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-3.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-4.c b/gcc/testsuite/gcc.dg/pr88784-4.c
new file mode 100644
index 00000000000..a9aa74cb9c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-4.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x > y && x == 0 --> false */
+  return x > y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x < y && x == UINT_MAX --> false */
+  return x < y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x > y && x == INT_MIN --> false */
+  return x > y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x < y && x == INT_MAX --> false */
+  return x < y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " == " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " > " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " < " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-5.c b/gcc/testsuite/gcc.dg/pr88784-5.c
new file mode 100644
index 00000000000..b147abbcfaf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-5.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-6.c b/gcc/testsuite/gcc.dg/pr88784-6.c
new file mode 100644
index 00000000000..6d5bd7b0c74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-6.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+_Bool and1(unsigned x, unsigned y)
+{
+  /* x <= y && x == 0 --> x == 0 */
+  return x <= y && x == 0;
+}
+
+_Bool and2(unsigned x, unsigned y)
+{
+  /* x >= y && x == UINT_MAX --> x == UINT_MAX */
+  return x >= y && x == UINT_MAX;
+}
+
+_Bool and3(signed x, signed y)
+{
+  /* x <= y && x == INT_MIN --> x == INT_MIN */
+  return x <= y && x == INT_MIN;
+}
+
+_Bool and4(signed x, signed y)
+{
+  /* x >= y && x == INT_MAX --> x == INT_MAX */
+  return x >= y && x == INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " <= " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " >= " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-7.c b/gcc/testsuite/gcc.dg/pr88784-7.c
new file mode 100644
index 00000000000..6577ff9e14d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-7.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " < " "ifcombine" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-8.c b/gcc/testsuite/gcc.dg/pr88784-8.c
new file mode 100644
index 00000000000..6bb56a91561
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-8.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x > y || x != 0 --> x != 0 */
+  return x > y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x < y || x != UINT_MAX --> x != UINT_MAX */
+  return x < y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x > y || x != INT_MIN --> x != INT_MIN */
+  return x > y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x < y || x != INT_MAX --> x != INT_MAX */
+  return x < y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " > " "optimized" } } */
+/* { dg-final { scan-tree-dump-not " < " "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/pr88784-9.c b/gcc/testsuite/gcc.dg/pr88784-9.c
new file mode 100644
index 00000000000..27e3281c555
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr88784-9.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ifcombine" } */
+
+#include <limits.h>
+
+_Bool or1(unsigned x, unsigned y)
+{
+  /* x <= y || x != 0 --> true */
+  return x <= y || x != 0;
+}
+
+_Bool or2(unsigned x, unsigned y)
+{
+  /* x >= y || x != UINT_MAX --> true */
+  return x >= y || x != UINT_MAX;
+}
+
+_Bool or3(signed x, signed y)
+{
+  /* x <= y || x != INT_MIN --> true */
+  return x <= y || x != INT_MIN;
+}
+
+_Bool or4(signed x, signed y)
+{
+  /* x >= y || x != INT_MAX --> true */
+  return x >= y || x != INT_MAX;
+}
+
+/* { dg-final { scan-tree-dump-not " != " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " <= " "ifcombine" } } */
+/* { dg-final { scan-tree-dump-not " >= " "ifcombine" } } */
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.
  2019-09-11 11:19                       ` Martin Liška
@ 2019-09-11 13:57                         ` Martin Liška
  2019-09-16  9:05                           ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:57 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 84 bytes --]

Hi.

Updated version of the patch that drops GENERIC
support in TREE codes.

Martin

[-- Attachment #2: 0004-Rewrite-first-part-of-or_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 4690 bytes --]

From 725f04c781c3d9cc2108b075201fc9ac7afb9a44 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:47:01 +0200
Subject: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules
	moved to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 87 +----------------------------------------------
 gcc/match.pd      | 28 +++++++++++++++
 2 files changed, 29 insertions(+), 86 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 23891fed930..dc8e8eef45c 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6051,93 +6051,8 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
     {
       int cmp = tree_int_cst_compare (op1b, op2b);
 
-      /* If we have (op1a != op1b), we should either be able to
-	 return that or TRUE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	    }
-	}
-      /* Likewise if the second comparison is a != comparison.  */
-      else if (code2 == NE_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return boolean_true_node;
-	      else
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	    }
-	}
-
-      /* See if an equality test is redundant with the other comparison.  */
-      else if (code1 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == EQ_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
       /* Chose the less restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
+      if ((code1 == LT_EXPR || code1 == LE_EXPR)
 	       && (code2 == LT_EXPR || code2 == LE_EXPR))
 	{
 	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
diff --git a/gcc/match.pd b/gcc/match.pd
index ac80dd7dd15..c465eabbb89 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2024,6 +2024,34 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       { constant_boolean_node (false, type); })
      )))))
 
+/* Convert (X == CST1) || (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (simplify
+   (bit_ior:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+      bool val;
+      switch (code2)
+	{
+	case EQ_EXPR: val = (cmp == 0); break;
+	case NE_EXPR: val = (cmp != 0); break;
+	case LT_EXPR: val = (cmp < 0); break;
+	case GT_EXPR: val = (cmp > 0); break;
+	case LE_EXPR: val = (cmp <= 0); break;
+	case GE_EXPR: val = (cmp >= 0); break;
+	default: gcc_unreachable ();
+	}
+     }
+     (switch
+      (if (code1 == EQ_EXPR && val) @4)
+      (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
+      (if (code1 == NE_EXPR && !val) @3))))))
+
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.
  2019-09-11 11:19                       ` Martin Liška
@ 2019-09-11 13:57                         ` Martin Liška
  2019-09-16  9:07                           ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:57 UTC (permalink / raw)
  To: Richard Biener, Li Jia He
  Cc: Andrew Pinski, Jeff Law, GCC Patches, Segher Boessenkool,
	wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 84 bytes --]

Hi.

Updated version of the patch that drops GENERIC
support in TREE codes.

Martin

[-- Attachment #2: 0005-Rewrite-second-part-of-or_comparisons_1-into-match.p.patch --]
[-- Type: text/x-patch, Size: 4442 bytes --]

From 548ff649ae56e2f60ba4b2537d97c5bf085248d5 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:59:36 +0200
Subject: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* gimple-fold.c (or_comparisons_1): Remove rules moved
	to ...
	* match.pd: ... here.
---
 gcc/gimple-fold.c | 45 ---------------------------------------------
 gcc/match.pd      | 38 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 38 insertions(+), 45 deletions(-)

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index dc8e8eef45c..5b79ebd711f 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6043,51 +6043,6 @@ or_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* Chose the less restrictive of two < or <= comparisons.  */
-      if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Likewise chose the less restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	  else
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LT_EXPR && code2 == GT_EXPR)
-		   || (code1 == GT_EXPR && code2 == LT_EXPR)))
-	return fold_build2 (NE_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for less/greater pairs that don't restrict the range at all.  */
-      else if (cmp >= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_true_node;
-      else if (cmp <= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_true_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
diff --git a/gcc/match.pd b/gcc/match.pd
index c465eabbb89..08b382fd2b9 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2051,6 +2051,44 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       (if (code1 == NE_EXPR && val) { constant_boolean_node (true, type); })
       (if (code1 == NE_EXPR && !val) @3))))))
 
+/* Convert (X OP1 CST1) || (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (simplify
+  (bit_ior (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+   (with
+    {
+     int cmp = tree_int_cst_compare (@1, @2);
+    }
+    (switch
+     /* Choose the more restrictive of two < or <= comparisons.  */
+     (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	  && (code2 == LT_EXPR || code2 == LE_EXPR))
+      (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+       @4
+       @3))
+     /* Likewise chose the more restrictive of two > or >= comparisons.  */
+     (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	  && (code2 == GT_EXPR || code2 == GE_EXPR))
+      (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+       @4
+       @3))
+     /* Check for singleton ranges.  */
+     (if (cmp == 0
+	  && ((code1 == LT_EXPR && code2 == GT_EXPR)
+	      || (code1 == GT_EXPR && code2 == LT_EXPR)))
+      (ne @0 @2))
+     /* Check for disjoint ranges.  */
+     (if (cmp >= 0
+	  && (code1 == LT_EXPR || code1 == LE_EXPR)
+	  && (code2 == GT_EXPR || code2 == GE_EXPR))
+      { constant_boolean_node (true, type); })
+     (if (cmp <= 0
+	  && (code1 == GT_EXPR || code1 == GE_EXPR)
+	  && (code2 == LT_EXPR || code2 == LE_EXPR))
+      { constant_boolean_node (true, type); })
+     )))))
 
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-11 13:19                                   ` Martin Liška
@ 2019-09-11 13:57                                     ` Martin Liška
  2019-09-16  9:04                                       ` Richard Biener
  0 siblings, 1 reply; 56+ messages in thread
From: Martin Liška @ 2019-09-11 13:57 UTC (permalink / raw)
  To: Richard Biener
  Cc: gcc-patches, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 3473 bytes --]

On 9/11/19 3:19 PM, Martin Liška wrote:
> On 9/11/19 2:43 PM, Richard Biener wrote:
>> On Wed, 11 Sep 2019, Martin Liška wrote:
>>
>>> I'm sending updated version of the patch where I changed
>>> from previous version:
>>> - more compact matching is used (note @3 and @4):
>>>   (and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
>>>
>>> Patch can bootstrap on x86_64-linux-gnu and survives regression tests.
>>>
>>> Ready to be installed?
>>
>> --- a/gcc/genmatch.c
>> +++ b/gcc/genmatch.c
>> @@ -1894,9 +1894,11 @@ dt_node *
>>  dt_node::append_simplify (simplify *s, unsigned pattern_no,
>>                           dt_operand **indexes)
>>  {
>> +  dt_simplify *s2;
>>    dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
>>    for (unsigned i = 0; i < kids.length (); ++i)
>> -    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
>> +    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
>> +       && s->match->location != s2->s->match->location)
>>        {
>>
>> can you retain the warning for verbose >= 1 please?  And put in
>> a comment that duplicates are sometimes hard to avoid with
>> nested for so this keeps match.pd sources small.
> 
> Sure.
> 
>>
>> +  /* Function maybe_fold_comparisons_from_match_pd creates temporary
>> +     SSA_NAMEs.  */
>> +  if (TREE_CODE (op1) == SSA_NAME && TREE_CODE (op2) == SSA_NAME)
>> +    {
>> +      gimple *s = SSA_NAME_DEF_STMT (op2);
>> +      if (is_gimple_assign (s))
>> +       return same_bool_comparison_p (op1, gimple_assign_rhs_code (s),
>> +                                      gimple_assign_rhs1 (s),
>> +                                      gimple_assign_rhs2 (s));
>> +      else
>> +       return false;
>> +    }
>>
>> when do you actually run into the need to add this?  The whole
>> same_bool_result_p/same_bool_comparison_p helpers look a bit
>> odd to me.  It shouldn't be special to the new temporaries
>> either so at least the comment looks out-of place.
> 
> At some point it was needed to handle gcc/testsuite/gcc.dg/pr46909.c
> test-case. Apparently, now the test-case is fine with the hunk. I will it
> removal of the hunk.

So it's not needed.

> 
>>
>> +      else if (op.code.is_tree_code ()
>> +              && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
>> +       {
>>
>> COMPARISON_CLASS_P ((tree_code)op.code)
>>
>> as was noted.
> 
> Won't work here:
> 
> /home/marxin/Programming/gcc/gcc/gimple-fold.c: In function ‘tree_node* maybe_fold_comparisons_from_match_pd(tree, tree_code, tree_code, tree, tree, tree_code, tree, tree)’:
> /home/marxin/Programming/gcc/gcc/tree.h:239:49: error: base operand of ‘->’ is not a pointer
>   239 | #define TREE_CODE(NODE) ((enum tree_code) (NODE)->base.code)
>       |                                                 ^~
> 
>>
>> Any particular reason you needed to swap the calls in
>> maybe_fold_and/or_comparisons?
>>
>> +(for code1 (eq ne)
>> + (for code2 (eq ne lt gt le ge)
>> +  (for and (truth_and bit_and)
>> +   (simplify
>>
>> You could save some code-bloat with writing
>>
>>   (for and (
>> #if GENERIC
>>   truth_and
>> #endif
>>   bit_and)
>>
>> but since you are moving the patterns from GIMPLE code I'd say
>> simply remove truth_and and that innermost for?
> 
> I'm gonna drop the generic tree codes support.

It's dropped in the updated patch.

Martin

> 
> Martin
> 
>>
>> Otherwise OK.
>>
>> Thanks,
>> Richard.
>>
>>
>>
>>
>>> Thanks,
>>> Martin
>>>
>>
> 


[-- Attachment #2: 0003-Rewrite-part-of-and_comparisons_1-into-match.pd.patch --]
[-- Type: text/x-patch, Size: 10878 bytes --]

From f4e6cf9aec14111a35b1c8d641f83ec355d8c7e0 Mon Sep 17 00:00:00 2001
From: Martin Liska <mliska@suse.cz>
Date: Fri, 6 Sep 2019 12:34:49 +0200
Subject: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.

gcc/ChangeLog:

2019-09-09  Martin Liska  <mliska@suse.cz>

	* genmatch.c (dt_node::append_simplify): Do not print
	warning when we have duplicate patterns belonging
	to a same simplify rule.
	* gimple-fold.c (and_comparisons_1): Remove matching moved to match.pd.
	(maybe_fold_comparisons_from_match_pd): Handle
	tcc_comparison as a results.
	(maybe_fold_and_comparisons):Call maybe_fold_comparisons_from_match_pd
	first.
	(maybe_fold_or_comparisons): Likewise.
	* match.pd: Handle (X == CST1) && (X OP2 CST2) conditions.
---
 gcc/genmatch.c    |   7 +-
 gcc/gimple-fold.c | 161 ++++++----------------------------------------
 gcc/match.pd      |  66 +++++++++++++++++++
 3 files changed, 93 insertions(+), 141 deletions(-)

diff --git a/gcc/genmatch.c b/gcc/genmatch.c
index 2e7bf27eeda..cede432cdc9 100644
--- a/gcc/genmatch.c
+++ b/gcc/genmatch.c
@@ -1894,10 +1894,15 @@ dt_node *
 dt_node::append_simplify (simplify *s, unsigned pattern_no,
 			  dt_operand **indexes)
 {
+  dt_simplify *s2;
   dt_simplify *n = new dt_simplify (s, pattern_no, indexes);
   for (unsigned i = 0; i < kids.length (); ++i)
-    if (dt_simplify *s2 = dyn_cast <dt_simplify *> (kids[i]))
+    if ((s2 = dyn_cast <dt_simplify *> (kids[i]))
+	&& (verbose >= 1
+	    || s->match->location != s2->s->match->location))
       {
+	/* With a nested patters, it's hard to avoid these in order
+	   to keep match.pd rules relatively small.  */
 	warning_at (s->match->location, "duplicate pattern");
 	warning_at (s2->s->match->location, "previous pattern defined here");
 	print_operand (s->match, stderr);
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 6d9ba367839..23891fed930 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -5620,136 +5620,6 @@ and_comparisons_1 (tree type, enum tree_code code1, tree op1a, tree op1b,
 	return t;
     }
 
-  /* If both comparisons are of the same value against constants, we might
-     be able to merge them.  */
-  if (operand_equal_p (op1a, op2a, 0)
-      && TREE_CODE (op1b) == INTEGER_CST
-      && TREE_CODE (op2b) == INTEGER_CST)
-    {
-      int cmp = tree_int_cst_compare (op1b, op2b);
-
-      /* If we have (op1a == op1b), we should either be able to
-	 return that or FALSE, depending on whether the constant op1b
-	 also satisfies the other comparison against op2b.  */
-      if (code1 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp < 0); break;
-	    case GT_EXPR: val = (cmp > 0); break;
-	    case LE_EXPR: val = (cmp <= 0); break;
-	    case GE_EXPR: val = (cmp >= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-      /* Likewise if the second comparison is an == comparison.  */
-      else if (code2 == EQ_EXPR)
-	{
-	  bool done = true;
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp > 0); break;
-	    case GT_EXPR: val = (cmp < 0); break;
-	    case LE_EXPR: val = (cmp >= 0); break;
-	    case GE_EXPR: val = (cmp <= 0); break;
-	    default: done = false;
-	    }
-	  if (done)
-	    {
-	      if (val)
-		return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	      else
-		return boolean_false_node;
-	    }
-	}
-
-      /* Same business with inequality tests.  */
-      else if (code1 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code2)
-	    {
-	    case EQ_EXPR: val = (cmp != 0); break;
-	    case NE_EXPR: val = (cmp == 0); break;
-	    case LT_EXPR: val = (cmp >= 0); break;
-	    case GT_EXPR: val = (cmp <= 0); break;
-	    case LE_EXPR: val = (cmp > 0); break;
-	    case GE_EXPR: val = (cmp < 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-      else if (code2 == NE_EXPR)
-	{
-	  bool val;
-	  switch (code1)
-	    {
-	    case EQ_EXPR: val = (cmp == 0); break;
-	    case NE_EXPR: val = (cmp != 0); break;
-	    case LT_EXPR: val = (cmp <= 0); break;
-	    case GT_EXPR: val = (cmp >= 0); break;
-	    case LE_EXPR: val = (cmp < 0); break;
-	    case GE_EXPR: val = (cmp > 0); break;
-	    default:
-	      val = false;
-	    }
-	  if (val)
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	}
-
-      /* Chose the more restrictive of two < or <= comparisons.  */
-      else if ((code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	{
-	  if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Likewise chose the more restrictive of two > or >= comparisons.  */
-      else if ((code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	{
-	  if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
-	    return fold_build2 (code1, boolean_type_node, op1a, op1b);
-	  else
-	    return fold_build2 (code2, boolean_type_node, op2a, op2b);
-	}
-
-      /* Check for singleton ranges.  */
-      else if (cmp == 0
-	       && ((code1 == LE_EXPR && code2 == GE_EXPR)
-		   || (code1 == GE_EXPR && code2 == LE_EXPR)))
-	return fold_build2 (EQ_EXPR, boolean_type_node, op1a, op2b);
-
-      /* Check for disjoint ranges. */
-      else if (cmp <= 0
-	       && (code1 == LT_EXPR || code1 == LE_EXPR)
-	       && (code2 == GT_EXPR || code2 == GE_EXPR))
-	return boolean_false_node;
-      else if (cmp >= 0
-	       && (code1 == GT_EXPR || code1 == GE_EXPR)
-	       && (code2 == LT_EXPR || code2 == LE_EXPR))
-	return boolean_false_node;
-    }
-
   /* Perhaps the first comparison is (NAME != 0) or (NAME == 1) where
      NAME's definition is a truth value.  See if there are any simplifications
      that can be done against the NAME's definition.  */
@@ -5899,6 +5769,16 @@ maybe_fold_comparisons_from_match_pd (tree type, enum tree_code code,
 	  else
 	    return res;
 	}
+      else if (op.code.is_tree_code ()
+	       && TREE_CODE_CLASS ((tree_code)op.code) == tcc_comparison)
+	{
+	  tree op0 = op.ops[0];
+	  tree op1 = op.ops[1];
+	  if (op0 == lhs1 || op0 == lhs2 || op1 == lhs1 || op1 == lhs2)
+	    return NULL_TREE;  /* not simple */
+
+	  return build2 ((enum tree_code)op.code, op.type, op0, op1);
+	}
     }
 
   return NULL_TREE;
@@ -5916,17 +5796,18 @@ maybe_fold_and_comparisons (tree type,
 			    enum tree_code code1, tree op1a, tree op1b,
 			    enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
-    return t;
-
-  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
-    return t;
 
   if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_AND_EXPR, code1,
 						     op1a, op1b, code2, op2a,
 						     op2b))
     return t;
 
+  if (tree t = and_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+    return t;
+
+  if (tree t = and_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+    return t;
+
   return NULL_TREE;
 }
 
@@ -6391,15 +6272,15 @@ maybe_fold_or_comparisons (tree type,
 			   enum tree_code code1, tree op1a, tree op1b,
 			   enum tree_code code2, tree op2a, tree op2b)
 {
-  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
+  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
+						     op1a, op1b, code2, op2a,
+						     op2b))
     return t;
 
-  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
+  if (tree t = or_comparisons_1 (type, code1, op1a, op1b, code2, op2a, op2b))
     return t;
 
-  if (tree t = maybe_fold_comparisons_from_match_pd (type, BIT_IOR_EXPR, code1,
-						     op1a, op1b, code2, op2a,
-						     op2b))
+  if (tree t = or_comparisons_1 (type, code2, op2a, op2b, code1, op1a, op1b))
     return t;
 
   return NULL_TREE;
diff --git a/gcc/match.pd b/gcc/match.pd
index 2ca88000cad..ac80dd7dd15 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -1958,6 +1958,72 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (eqne == NE_EXPR)
      { constant_boolean_node (true, type); }))))
 
+/* Convert (X == CST1) && (X OP2 CST2) to a known value
+   based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
+
+(for code1 (eq ne)
+ (for code2 (eq ne lt gt le ge)
+  (simplify
+   (bit_and:c (code1@3 @0 INTEGER_CST@1) (code2@4 @0 INTEGER_CST@2))
+    (with
+     {
+      int cmp = tree_int_cst_compare (@1, @2);
+      bool val;
+      switch (code2)
+	 {
+	case EQ_EXPR: val = (cmp == 0); break;
+	case NE_EXPR: val = (cmp != 0); break;
+	case LT_EXPR: val = (cmp < 0); break;
+	case GT_EXPR: val = (cmp > 0); break;
+	case LE_EXPR: val = (cmp <= 0); break;
+	case GE_EXPR: val = (cmp >= 0); break;
+	default: gcc_unreachable ();
+	}
+     }
+     (switch
+      (if (code1 == EQ_EXPR && val) @3)
+      (if (code1 == EQ_EXPR && !val) { constant_boolean_node (false, type); })
+      (if (code1 == NE_EXPR && !val) @4))))))
+
+/* Convert (X OP1 CST1) && (X OP2 CST2).  */
+
+(for code1 (lt le gt ge)
+ (for code2 (lt le gt ge)
+  (simplify
+  (bit_and (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))
+   (with
+    {
+     int cmp = tree_int_cst_compare (@1, @2);
+    }
+    (switch
+     /* Choose the more restrictive of two < or <= comparisons.  */
+     (if ((code1 == LT_EXPR || code1 == LE_EXPR)
+	  && (code2 == LT_EXPR || code2 == LE_EXPR))
+      (if ((cmp < 0) || (cmp == 0 && code1 == LT_EXPR))
+       @3
+       @4))
+     /* Likewise chose the more restrictive of two > or >= comparisons.  */
+     (if ((code1 == GT_EXPR || code1 == GE_EXPR)
+	  && (code2 == GT_EXPR || code2 == GE_EXPR))
+      (if ((cmp > 0) || (cmp == 0 && code1 == GT_EXPR))
+       @3
+       @4))
+     /* Check for singleton ranges.  */
+     (if (cmp == 0
+	  && ((code1 == LE_EXPR && code2 == GE_EXPR)
+	    || (code1 == GE_EXPR && code2 == LE_EXPR)))
+      (eq @0 @1))
+     /* Check for disjoint ranges.  */
+     (if (cmp <= 0
+	  && (code1 == LT_EXPR || code1 == LE_EXPR)
+	  && (code2 == GT_EXPR || code2 == GE_EXPR))
+      { constant_boolean_node (false, type); })
+     (if (cmp >= 0
+	  && (code1 == GT_EXPR || code1 == GE_EXPR)
+	  && (code2 == LT_EXPR || code2 == LE_EXPR))
+      { constant_boolean_node (false, type); })
+     )))))
+
 /* We can't reassociate at all for saturating types.  */
 (if (!TYPE_SATURATING (type))
 
-- 
2.23.0


^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-11 13:57                                     ` Martin Liška
@ 2019-09-16  9:04                                       ` Richard Biener
  2019-09-16 13:47                                         ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-16  9:04 UTC (permalink / raw)
  To: Martin Liška
  Cc: gcc-patches, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 303 bytes --]

On Wed, 11 Sep 2019, Martin Liška wrote:

> On 9/11/19 3:19 PM, Martin Liška wrote:
> > On 9/11/19 2:43 PM, Richard Biener wrote:
> >> Any particular reason you needed to swap the calls in
> >> maybe_fold_and/or_comparisons?

You didn't answer this, besides that the patch is OK.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd.
  2019-09-11 13:57                         ` Martin Liška
@ 2019-09-16  9:05                           ` Richard Biener
  0 siblings, 0 replies; 56+ messages in thread
From: Richard Biener @ 2019-09-16  9:05 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 151 bytes --]

On Wed, 11 Sep 2019, Martin Liška wrote:

> Hi.
> 
> Updated version of the patch that drops GENERIC
> support in TREE codes.

OK.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.
  2019-09-11 13:57                         ` Martin Liška
@ 2019-09-16  9:07                           ` Richard Biener
  2019-09-16 14:23                             ` Martin Liška
  0 siblings, 1 reply; 56+ messages in thread
From: Richard Biener @ 2019-09-16  9:07 UTC (permalink / raw)
  To: Martin Liška
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

[-- Attachment #1: Type: text/plain, Size: 349 bytes --]

On Wed, 11 Sep 2019, Martin Liška wrote:

> Hi.
> 
> Updated version of the patch that drops GENERIC
> support in TREE codes.

+  (bit_ior (code1:c@3 @0 INTEGER_CST@1) (code2:c@4 @0 INTEGER_CST@2))

the :c on both code1 and code2 are not necessary since the constant
is always second via canonicalization.

OK with that removed.

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 3/5] Rewrite part of and_comparisons_1 into match.pd.
  2019-09-16  9:04                                       ` Richard Biener
@ 2019-09-16 13:47                                         ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-16 13:47 UTC (permalink / raw)
  To: Richard Biener
  Cc: gcc-patches, Li Jia He, Andrew Pinski, Jeff Law,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/16/19 5:04 AM, Richard Biener wrote:
> On Wed, 11 Sep 2019, Martin Liška wrote:
> 
>> On 9/11/19 3:19 PM, Martin Liška wrote:
>>> On 9/11/19 2:43 PM, Richard Biener wrote:
>>>> Any particular reason you needed to swap the calls in
>>>> maybe_fold_and/or_comparisons?
> 
> You didn't answer this, besides that the patch is OK.

Ah, sorry.

No, there's not any particular reason. My motivation was that I moved
the patterns from the beginning of and_comparisons_1 to match.pd.
So that I wanted to begin with the maybe_fold_comparisons_from_match_pd.

I'll put it back to the original order.

Martin

> 
> Thanks,
> Richard.
> 

^ permalink raw reply	[flat|nested] 56+ messages in thread

* Re: [PATCH 5/5] Rewrite second part of or_comparisons_1 into match.pd.
  2019-09-16  9:07                           ` Richard Biener
@ 2019-09-16 14:23                             ` Martin Liška
  0 siblings, 0 replies; 56+ messages in thread
From: Martin Liška @ 2019-09-16 14:23 UTC (permalink / raw)
  To: Richard Biener
  Cc: Li Jia He, Andrew Pinski, Jeff Law, GCC Patches,
	Segher Boessenkool, wschmidt, Martin Liska

On 9/16/19 5:07 AM, Richard Biener wrote:
> the :c on both code1 and code2 are not necessary since the constant
> is always second via canonicalization.

Fine, fixed.

Btw. I've just installed the whole patchset.

Martin

^ permalink raw reply	[flat|nested] 56+ messages in thread

end of thread, other threads:[~2019-09-16 14:23 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-06-27  6:12 [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Li Jia He
2019-06-27 15:48 ` Jeff Law
2019-06-28  4:55   ` Li Jia He
2019-06-28 17:02     ` Andrew Pinski
2019-07-01  7:31       ` Richard Biener
2019-07-02  7:41         ` Li Jia He
2019-07-02  8:09           ` Richard Biener
2019-07-02  8:51             ` Richard Biener
2019-07-16  6:54               ` Li Jia He
2019-08-30 11:16                 ` Martin Liška
2019-09-05 13:01                 ` Richard Biener
2019-09-05 18:47                   ` Martin Liška
2019-09-06  8:01                     ` Richard Biener
2019-09-06  8:04                       ` Martin Liška
2019-09-06 10:13                   ` [PATCH 1/2] Auto-generate maybe_fold_and/or_comparisons from match.pd Martin Liška
2019-09-09 12:23                     ` Martin Liška
2019-09-09 13:10                       ` Marc Glisse
2019-09-09 13:30                         ` Martin Liška
2019-09-09 13:39                           ` Richard Biener
2019-09-09 13:10                       ` Richard Biener
2019-09-09 13:40                         ` Martin Liška
2019-09-09 13:42                           ` Richard Biener
2019-09-09 13:45                             ` Martin Liška
2019-09-09 13:55                               ` Richard Biener
2019-09-10  7:40                                 ` Martin Liška
     [not found]                                   ` <ba4ec7b3-0d0d-ca7b-b2d9-2f34478a23f4@linux.ibm.com>
2019-09-11  8:51                                     ` Martin Liška
2019-09-11 11:16                                   ` Martin Liška
2019-09-11 12:23                                     ` Richard Biener
2019-09-11 13:55                                       ` Martin Liška
2019-09-09 12:24                     ` [PATCH 4/5] Rewrite first part of or_comparisons_1 into match.pd Martin Liška
2019-09-11 11:19                       ` Martin Liška
2019-09-11 13:57                         ` Martin Liška
2019-09-16  9:05                           ` Richard Biener
2019-09-09 12:24                     ` [PATCH 3/5] Rewrite part of and_comparisons_1 " Martin Liška
2019-09-09 13:41                       ` Martin Liška
2019-09-10  7:41                         ` Martin Liška
2019-09-10 11:19                           ` Marc Glisse
2019-09-11  8:27                             ` Martin Liška
2019-09-11 11:18                               ` Martin Liška
2019-09-11 12:44                                 ` Richard Biener
2019-09-11 13:19                                   ` Martin Liška
2019-09-11 13:57                                     ` Martin Liška
2019-09-16  9:04                                       ` Richard Biener
2019-09-16 13:47                                         ` Martin Liška
2019-09-10  8:52                         ` Bernhard Reutner-Fischer
2019-09-11  8:11                           ` Martin Liška
2019-09-09 12:25                     ` [PATCH 5/5] Rewrite second part of or_comparisons_1 " Martin Liška
2019-09-11 11:19                       ` Martin Liška
2019-09-11 13:57                         ` Martin Liška
2019-09-16  9:07                           ` Richard Biener
2019-09-16 14:23                             ` Martin Liška
2019-09-05 13:17                 ` [PATCH][middle-end/88784] Middle end is missing some optimizations about unsigned Richard Biener
2019-09-05 18:47                   ` Martin Liška
2019-09-06 10:14                   ` [PATCH 2/2] Fix PR88784, middle " Martin Liška
2019-09-11 13:08                     ` Richard Biener
2019-09-11 13:56                       ` Martin Liška

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).