Hello,

For unsigned A, B, 'A > -1 / B' is a nice predicate for checking whether 'A*B'
overflows (or 'B && A > -1 / B' if B may be zero).  Let's optimize it to an
invocation of __builtin_mul_overflow to avoid the divide operation.

The following patch implements that as a match.pd transformation.  It looks
like there's a similar thing going on for add/sub overflow check in
tree-ssa-math-opts, but handling this in match.pd seems reasonable.

(user code using the above test would probably also compute 'A*B' a few
statements later; notably, today GCC cannot CSE plain 'A*B' to REALPART_EXPR
of the builtin call on GIMPLE; on x86 it gets cleaned up on RTL)

Thanks to Marc for helping get this in shape on the Bugzilla.

Bootstrapped and regtested on x86_64, OK for trunk?

gcc/
2016-05-28  Alexander Monakov  <amona...@ispras.ru>
        Marc Glisse  <marc.gli...@inria.fr>

        PR tree-optimization/71289
        * match.pd (-1 / B < A, A > -1 / B): New transformations.

gcc/testsuite/
2016-05-28  Alexander Monakov  <amona...@ispras.ru>

        PR tree-optimization/71289
        * gcc.dg/pr71289.c: New test.

diff --git a/gcc/match.pd b/gcc/match.pd
index 8d05e86..953c070 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -2657,6 +2657,25 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
        && types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
    (out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
 
+/* For unsigned operands, A > -1 / B checks whether A * B would overflow.
+   Simplify it to __builtin_mul_overflow (A, B, <unused>).  */
+/* -1 / B < A */
+(for cmp (lt ge)
+     out (ne eq)
+ (simplify
+  (cmp (trunc_div:s integer_all_onesp @1) @0)
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && !VECTOR_TYPE_P (TREE_TYPE (@0)))
+   (with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
+    (out (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
+
+/* A > -1 / B */
+(for cmp (gt le)
+     out (ne eq)
+ (simplify
+  (cmp @0 (trunc_div:s integer_all_onesp @1))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)) && !VECTOR_TYPE_P (TREE_TYPE (@0)))
+   (with { tree t = TREE_TYPE (@0), cpx = build_complex_type (t); }
+    (out (imagpart (IFN_MUL_OVERFLOW:cpx @0 @1)) { build_zero_cst (t); })))))
 
 /* Simplification of math builtins.  These rules must all be optimizations
    as well as IL simplifications.  If there is a possibility that the new
diff --git a/gcc/testsuite/gcc.dg/pr71289.c b/gcc/testsuite/gcc.dg/pr71289.c
new file mode 100644
index 0000000..39837b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr71289.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized-raw" } */
+
+int f(unsigned a, unsigned b, unsigned *c)
+{
+  if (a > -1 / b)
+    return -1;
+  *c = a * b;
+  return 0;
+}
+
+void g(unsigned long long a, unsigned long long b, unsigned long long *c)
+{
+  if (a <= -1 / b)
+    *c = a * b;
+}
+
+/* { dg-final { scan-tree-dump-not "trunc_div_expr" "optimized" } } */

Reply via email to