(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
"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. */
--- /dev/null
+/* 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" } } */
--- /dev/null
+/* 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" } } */