Optimize combination of comparisons to dec+compare
authorEugene Rozenfeld <erozen@microsoft.com>
Thu, 10 Dec 2020 00:44:25 +0000 (16:44 -0800)
committerRichard Biener <rguenther@suse.de>
Wed, 20 Jan 2021 15:31:46 +0000 (16:31 +0100)
This patch adds patterns for optimizing
x < y || y == XXX_MIN to x <= y-1
x >= y && y != 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

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

gcc/testsuite
* gcc.dg/pr96674.c: New tests.

gcc/match.pd
gcc/testsuite/gcc.dg/pr96674.c [new file with mode: 0644]

index 7158e983d218a3dc13aaca28cba86513e2959e5d..05e7ba9a3336830e06c5463c407f9ede54d09244 100644 (file)
@@ -2159,6 +2159,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
     (if (eqne == NE_EXPR)
      { constant_boolean_node (true, type); }))))
 
+/* y == XXX_MIN || x < y --> x <= y - 1 */
+(simplify
+ (bit_ior:c (eq:s @1 min_value) (lt:s @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); }))))
+
+/* y != XXX_MIN && x >= y --> x > y - 1 */
+(simplify
+ (bit_and:c (ne:s @1 min_value) (ge:s @0 @1))
+  (if (INTEGRAL_TYPE_P (TREE_TYPE (@1))
+       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@1)))
+  (gt @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 (file)
index 0000000..194ce2e
--- /dev/null
@@ -0,0 +1,40 @@
+/* { dg-do run } */
+/* { dg-options "-O -fdump-tree-optimized -fwrapv" } */
+
+#include <limits.h>
+#include <stdbool.h>
+
+bool __attribute__ ((noipa)) test1 (unsigned a, unsigned b)
+{
+    return (b == 0) | (a < b);
+}
+
+bool __attribute__ ((noipa)) test2 (int a, int b)
+{
+    return (b == INT_MIN) | (a < b);
+}
+
+bool __attribute__ ((noipa)) test3 (unsigned a, unsigned b)
+{
+    return (b != 0) & (a >= b);
+}
+
+bool __attribute__ ((noipa)) test4 (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) ||
+        test3 (1, 0) || test3 (1, 2) || !test3 (2, 1) ||
+        test4 (1, INT_MIN) || test4 (1, 2) || !test4 (2, 1)) {
+        __builtin_abort();     
+    }          
+
+    return 0;
+}
+
+/* { dg-final { scan-tree-dump-times "\\+ 4294967295;" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "\\+ -1;" 2 "optimized" } } */