match.pd: unsigned A - B > A --> A < B

2016-04-27  Marc Glisse  <marc.glisse@inria.fr>

gcc/
	* match.pd (A - B > A, A + B < A): New transformations.

gcc/testsuite/
	* gcc.dg/tree-ssa/overflow-2.c: New testcase.
	* gcc.dg/tree-ssa/minus-ovf.c: Likewise.

From-SVN: r235537
This commit is contained in:
Marc Glisse 2016-04-27 23:30:27 +02:00 committed by Marc Glisse
parent 044a73da40
commit 3563f78f97
5 changed files with 155 additions and 0 deletions

View File

@ -1,3 +1,7 @@
2016-04-27 Marc Glisse <marc.glisse@inria.fr>
* match.pd (A - B > A, A + B < A): New transformations.
2016-04-27 Patrick Palka <ppalka@gcc.gnu.org>
* genattrtab.c (write_test_expr): New parameter EMIT_PARENS

View File

@ -2508,6 +2508,60 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(out @0 { wide_int_to_tree (TREE_TYPE (@0), wi::max_value
(TYPE_PRECISION (TREE_TYPE (@0)), UNSIGNED) - @1); }))))
/* 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)
&& ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& 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)
&& ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& 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. */
/* A < A - B */
(for cmp (lt ge)
out (ne eq)
(simplify
(cmp @0 (realpart (IFN_SUB_OVERFLOW@2 @0 @1)))
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
(out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
/* A - B > A */
(for cmp (gt le)
out (ne eq)
(simplify
(cmp (realpart (IFN_SUB_OVERFLOW@2 @0 @1)) @0)
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
(out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
/* A + B < A */
(for cmp (lt ge)
out (ne eq)
(simplify
(cmp (realpart (IFN_ADD_OVERFLOW:c@2 @0 @1)) @0)
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
(out (imagpart @2) { build_zero_cst (TREE_TYPE (@0)); }))))
/* A > A + B */
(for cmp (gt le)
out (ne eq)
(simplify
(cmp @0 (realpart (IFN_ADD_OVERFLOW:c@2 @0 @1)))
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& types_match (TREE_TYPE (@0), TREE_TYPE (@1)))
(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

View File

@ -1,3 +1,8 @@
2016-04-27 Marc Glisse <marc.glisse@inria.fr>
* gcc.dg/tree-ssa/overflow-2.c: New testcase.
* gcc.dg/tree-ssa/minus-ovf.c: Likewise.
2015-04-27 Ryan Burn <contact@rnburn.com>
PR c++/69024

View File

@ -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" } } */

View File

@ -0,0 +1,68 @@
/* { 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 j2(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return r < b;
}
int k(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return a > r;
}
int k2(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return b > r;
}
int l(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return r >= a;
}
int l2(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return r >= b;
}
int m(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return a <= r;
}
int m2(unsigned a, unsigned b) {
unsigned r;
carry = __builtin_add_overflow(a, b, &r);
return b <= r;
}
/* { dg-final { scan-tree-dump-not "(le|lt|ge|gt)_expr" "optimized" } } */
/* { dg-final { scan-tree-dump-times "ADD_OVERFLOW" 8 "optimized" } } */
/* { dg-final { scan-tree-dump-times "SUB_OVERFLOW" 4 "optimized" } } */