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  <heli...@linux.ibm.com>
            Qi Feng  <ffen...@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  <heli...@linux.ibm.com>
            Qi Feng  <ffen...@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

Reply via email to