From 39215c58f5f640920d81cbe43503342c8b518cd9 Mon Sep 17 00:00:00 2001
From: Eugene Rozenfeld <erozen@microsoft.com>
Date: Wed, 9 Dec 2020 16:44:25 -0800
Subject: [PATCH] Optimize combination of comparisons to dec+compare

This patch adds a pattern for optimizing
x < y || x == XXX_MIN to x <= y-1
if y is an integer with TYPE_OVERFLOW_WRAPS.

This fixes pr96674.

Tested on x86_64-pc-linux-gnu.

For this function

bool f(unsigned a, unsigned b)
{
    return (b == 0) | (a < b);
}

the code without the patch is

test   esi,esi
sete   al
cmp    esi,edi
seta   dl
or     eax,edx
ret

the code with the patch is

sub    esi,0x1
cmp    esi,edi
setae  al
ret

gcc/
PR tree-optimization/96674
* match.pd: New pattern x < y || x == XXX_MIN --> x <= y - 1

gcc/testsuite
* gcc.dg/pr96674.c: New test.
---
 gcc/match.pd                   |  7 +++++++
 gcc/testsuite/gcc.dg/pr96674.c | 28 ++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/pr96674.c

diff --git a/gcc/match.pd b/gcc/match.pd
index 68201ff2e07..c29af540152 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2084,6 +2084,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (eqne == NE_EXPR)
      { constant_boolean_node (true, type); }))))
 
+/* x < y || x == XXX_MIN --> x <= y - 1 */
+(simplify
+ (bit_ior (eq @1 min_value) (lt @0 @1))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+  (le @0 (minus @1 { build_int_cst (TREE_TYPE (@1), 1); }))))
+
 /* Convert (X == CST1) && (X OP2 CST2) to a known value
    based on CST1 OP2 CST2.  Similarly for (X != CST1).  */
 
diff --git a/gcc/testsuite/gcc.dg/pr96674.c b/gcc/testsuite/gcc.dg/pr96674.c
new file mode 100644
index 00000000000..c7f20bffabb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr96674.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-optimized -fwrapv" } */
+
+#include <limits.h>
+#include <stdbool.h>
+
+bool __attribute__ ((noinline)) test1 (unsigned a, unsigned b)
+{
+    return (b == 0) | (a < b);
+}
+
+bool __attribute__ ((noinline)) test2 (int a, int b)
+{
+    return (b == INT_MIN) | (a < b);
+}
+
+int main()
+{
+    if (!test1 (1, 0) || !test1 (1, 2) || test1 (2, 1) ||
+        !test2 (1, INT_MIN) || !test2 (1, 2) || test2 (2, 1)) {
+        __builtin_abort();	
+    }
+
+    return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\\+ 4294967295;" 1 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\+ -1;" 1 "optimized" } } */
-- 
2.17.1

