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 <[email protected]>
Qi Feng <[email protected]>
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 <[email protected]>
Qi Feng <[email protected]>
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