diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/match.pd | 43 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c | 38 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c | 37 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c | 2 |
4 files changed, 118 insertions, 2 deletions
diff --git a/gcc/match.pd b/gcc/match.pd index baa6d2f..e73bb7e 100644 --- a/gcc/match.pd +++ b/gcc/match.pd @@ -9030,6 +9030,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) (cmp @0 { TREE_OVERFLOW (res) ? drop_tree_overflow (res) : res; })))))))) (for cmp (lt le gt ge) + rcmp (gt ge lt le) (for op (plus minus) rop (minus plus) (simplify @@ -9057,7 +9058,47 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT) "X cmp C2 -+ C1"), WARN_STRICT_OVERFLOW_COMPARISON); } - (cmp @0 { res; }))))))))) + (cmp @0 { res; }))))) +/* For wrapping types, simplify the following cases of X +- C1 CMP C2: + + (a) If CMP is <= and C2 -+ C1 == +INF (1), simplify to X >= -INF -+ C1 + by observing the following: + + X +- C1 <= C2 + ==> -INF <= X +- C1 <= C2 (add left hand side which holds for any X, C1) + ==> -INF -+ C1 <= X <= C2 -+ C1 (add -+C1 to all 3 expressions) + ==> -INF -+ C1 <= X <= +INF (due to (1)) + ==> -INF -+ C1 <= X (eliminate the right hand side since it holds for any X) + + (b) Similarly, if CMP is >= and C2 -+ C1 == -INF (1): + + X +- C1 >= C2 + ==> +INF >= X +- C1 >= C2 (add left hand side which holds for any X, C1) + ==> +INF -+ C1 >= X >= C2 -+ C1 (add -+C1 to all 3 expressions) + ==> +INF -+ C1 >= X >= -INF (due to (1)) + ==> +INF -+ C1 >= X (eliminate the right hand side since it holds for any X) + + (c) The > and < cases are negations of (a) and (b), respectively. */ + (if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))) + (with + { + wide_int max = wi::max_value (TREE_TYPE (@0)); + wide_int min = wi::min_value (TREE_TYPE (@0)); + + wide_int c2 = rop == PLUS_EXPR + ? wi::add (wi::to_wide (@2), wi::to_wide (@1)) + : wi::sub (wi::to_wide (@2), wi::to_wide (@1)); + } + (if (((cmp == LE_EXPR || cmp == GT_EXPR) && wi::eq_p (c2, max)) + || ((cmp == LT_EXPR || cmp == GE_EXPR) && wi::eq_p (c2, min))) + (with + { + wide_int c1 = rop == PLUS_EXPR + ? wi::add (wi::bit_not (c2), wi::to_wide (@1)) + : wi::sub (wi::bit_not (c2), wi::to_wide (@1)); + tree c1_cst = wide_int_to_tree (TREE_TYPE (@0), c1); + } + (rcmp @0 { c1_cst; }))))))))) /* Invert sign of X in comparisons of the form C1 - X CMP C2. */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c new file mode 100644 index 0000000..b9e88ba --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c @@ -0,0 +1,38 @@ +/* PR tree-optimization/116024 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop1-details -fwrapv" } */ + +#include <stdint.h> +#include <limits.h> + +uint32_t f(void); + +int32_t i3(void) +{ + int32_t l = -10 + (int32_t)f(); + return l <= INT32_MAX - 10; // f() >= INT32_MIN + 10 +} + +int32_t i3a(void) +{ + int32_t l = -20 + (int32_t)f(); + return l < INT32_MAX - 19; // f() > INT32_MAX + 20 +} + +int32_t i3b(void) +{ + int32_t l = 30 + (int32_t)f(); + return l >= INT32_MIN + 30; // f() <= INT32_MAX - 30 +} + +int32_t i3c(void) +{ + int32_t l = 40 + (int32_t)f(); + return l > INT32_MIN + 39; // f() < INT32_MIN - 40 +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483638" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* >= -2147483628" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483617" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 2147483607" 1 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c new file mode 100644 index 0000000..f7ff077 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c @@ -0,0 +1,37 @@ +/* PR tree-optimization/116024 */ +/* { dg-do compile } */ +/* { dg-options "-O1 -fdump-tree-forwprop1-details" } */ + +#include <stdint.h> + +uint32_t f(void); + +int32_t i3(void) +{ + uint32_t l = 10 + (uint32_t)f(); + return l <= 9; // f() >= -10u +} + +int32_t i3a(void) +{ + uint32_t l = 20 + (uint32_t)f(); + return l < 20; // f() > -21u +} + +int32_t i3b(void) +{ + uint32_t l = 30 + (uint32_t)f(); + return l >= 30; // f() <= -31u +} + +int32_t i3c(void) +{ + uint32_t l = 40 + (uint32_t)f(); + return l > 39; // f() < -39u +} + +/* { dg-final { scan-tree-dump-times "Removing dead stmt:.*? \\+" 4 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 4294967285" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* > 4294967275" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967265" 1 "forwprop1" } } */ +/* { dg-final { scan-tree-dump-times "gimple_simplified to.* <= 4294967255" 1 "forwprop1" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c index 81c536c..bfcec67 100644 --- a/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c +++ b/gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c @@ -10,4 +10,4 @@ f1 (int x, int t) return t; } -/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #2" 1 } } */ +/* { dg-final { scan-assembler-times "cmn\\tw\[0-9\]+, #3" 1 } } */ |