diff mbox

Convert manual unsigned +/- overflow checking into {ADD,SUB}_OVERFLOW (PR target/67089)

Message ID alpine.DEB.2.02.1512042236070.25208@laptop-mg.saclay.inria.fr
State New
Headers show

Commit Message

Marc Glisse Dec. 4, 2015, 9:45 p.m. UTC
On Wed, 25 Nov 2015, Marc Glisse wrote:

>> So, I'd really prefer doing x-y>x to y>x only for single use.
>
> Ok

Let me post this patch (needs testing on x86, I only tested on ppc which 
does not implement the new optabs) so I can more easily find it again at 
next stage 1.

It produces imag()==0 or imag()!=0 because I think that's what Jakub's 
patch does.
diff mbox

Patch

Index: gcc/match.pd
===================================================================
--- gcc/match.pd	(revision 231300)
+++ gcc/match.pd	(working copy)
@@ -2396,20 +2396,62 @@  DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
       && types_match (type, TREE_TYPE (@0)))
   (non_lvalue @0)))
 /* Do not handle
    bool_var == 0 becomes !bool_var or
    bool_var != 1 becomes !bool_var
    here because that only is good in assignment context as long
    as we require a tcc_comparison in GIMPLE_CONDs where we'd
    replace if (x == 0) with tem = ~x; if (tem != 0) which is
    clearly less optimal and which we'll transform again in forwprop.  */
 
+/* To detect overflow in unsigned A - B, A < B is simpler than A - B > A.
+   However, the detection logic for SUB_OVERFLOW in tree-ssa-math-opts.c
+   expects the long form, so we restrict the transformation for now.  */
+(for cmp (gt le)
+ (simplify
+  (cmp (minus@2 @0 @1) @0)
+  (if (single_use (@2)
+       && TYPE_UNSIGNED (TREE_TYPE (@0))
+       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+   (cmp @1 @0))))
+(for cmp (lt ge)
+ (simplify
+  (cmp @0 (minus@2 @0 @1))
+  (if (single_use (@2)
+       && TYPE_UNSIGNED (TREE_TYPE (@0))
+       && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+   (cmp @0 @1))))
+/* Testing for overflow is unnecessary if we already know the result.  */
+(for cmp (lt ge)
+     out (ne eq)
+ (simplify
+  (cmp @0 (realpart (IFN_SUB_OVERFLOW@2 @0 @1)))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
+(for cmp (gt le)
+     out (ne eq)
+ (simplify
+  (cmp (realpart (IFN_SUB_OVERFLOW@2 @0 @1)) @0)
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
+(for cmp (lt ge)
+     out (ne eq)
+ (simplify
+  (cmp (realpart (IFN_ADD_OVERFLOW@2 @0 @1)) @0)
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
+(for cmp (gt le)
+     out (ne eq)
+ (simplify
+  (cmp @0 (realpart (IFN_ADD_OVERFLOW@2 @0 @1)))
+  (if (TYPE_UNSIGNED (TREE_TYPE (@0)))
+   (out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
 
 /* Simplification of math builtins.  These rules must all be optimizations
    as well as IL simplifications.  If there is a possibility that the new
    form could be a pessimization, the rule should go in the canonicalization
    section that follows this one.
 
    Rules can generally go in this section if they satisfy one of
    the following:
 
    - the rule describes an identity
Index: gcc/testsuite/gcc.dg/tree-ssa/minus-ovf.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/minus-ovf.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/minus-ovf.c	(working copy)
@@ -0,0 +1,24 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O -fdump-tree-optimized" } */
+
+int f(unsigned a, unsigned b) {
+  unsigned remove = a - b;
+  return remove > a;
+}
+
+int g(unsigned a, unsigned b) {
+  unsigned remove = a - b;
+  return remove <= a;
+}
+
+int h(unsigned a, unsigned b) {
+  unsigned remove = a - b;
+  return a < remove;
+}
+
+int i(unsigned a, unsigned b) {
+  unsigned remove = a - b;
+  return a >= remove;
+}
+
+/* { dg-final { scan-tree-dump-not "remove" "optimized" } } */
Index: gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c
===================================================================
--- gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/tree-ssa/overflow-1.c	(working copy)
@@ -0,0 +1,48 @@ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+int carry;
+int f(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_sub_overflow(a, b, &r);
+  return r > a;
+}
+int g(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_sub_overflow(a, b, &r);
+  return a < r;
+}
+int h(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_sub_overflow(a, b, &r);
+  return r <= a;
+}
+int i(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_sub_overflow(a, b, &r);
+  return a >= r;
+}
+int j(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_add_overflow(a, b, &r);
+  return r < a;
+}
+int k(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_add_overflow(a, b, &r);
+  return a > r;
+}
+int l(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_add_overflow(a, b, &r);
+  return r >= a;
+}
+int m(unsigned a, unsigned b) {
+  unsigned r;
+  carry = __builtin_add_overflow(a, b, &r);
+  return a <= r;
+}
+
+/* { dg-final { scan-tree-dump-not "(le|lt|ge|gt)_expr" "optimized" } } */
+/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 4 "optimized" } } */