aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/match.pd43
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr116024-2-fwrapv.c38
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr116024-2.c37
-rw-r--r--gcc/testsuite/gcc.target/aarch64/gtu_to_ltu_cmp_1.c2
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 } } */