--- /dev/null
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+
+unsigned f1(unsigned i, unsigned j) {
+ if (j != i) __builtin_unreachable();
+ return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f2(unsigned i, unsigned j) {
+ if (j > i) __builtin_unreachable();
+ return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f3(unsigned i, unsigned j) {
+ if (j >= i) __builtin_unreachable();
+ return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+unsigned f4(unsigned i, unsigned j) {
+ if (j <= i) __builtin_unreachable();
+ return __builtin_sub_overflow_p(i, j, (unsigned)0);
+}
+
+/* { dg-final { scan-tree-dump-times "return 0" 3 optimized } } */
+/* { dg-final { scan-tree-dump-times "return 1" 1 optimized } } */
+/* { dg-final { scan-tree-dump-not "SUB_OVERFLOW" optimized } } */
+/* { dg-final { scan-tree-dump-not "IMAGPART_EXPR" optimized } } */
enum tree_code subcode, tree type,
tree op0, tree op1, bool *ovf, gimple *s = NULL)
{
+ relation_kind rel = VREL_VARYING;
+ /* For subtraction see if relations could simplify it. */
+ if (s
+ && subcode == MINUS_EXPR
+ && types_compatible_p (TREE_TYPE (op0), TREE_TYPE (op1)))
+ {
+ rel = query->relation().query (s, op0, op1);
+ /* The result of the infinite precision subtraction of
+ the same values will be always 0. That will fit into any result
+ type. */
+ if (rel == VREL_EQ)
+ return true;
+ }
+
int_range_max vr0, vr1;
if (!query->range_of_expr (vr0, op0, s) || vr0.undefined_p ())
vr0.set_varying (TREE_TYPE (op0));
tree vr1min = wide_int_to_tree (TREE_TYPE (op1), vr1.lower_bound ());
tree vr1max = wide_int_to_tree (TREE_TYPE (op1), vr1.upper_bound ());
+ /* If op1 is not negative, op0 - op1 in infinite precision for op0 >= op1
+ will be always in [0, op0] and so if vr0max - vr1min fits into type,
+ there won't be any overflow. */
+ if ((rel == VREL_GT || rel == VREL_GE)
+ && tree_int_cst_sgn (vr1min) >= 0
+ && !arith_overflowed_p (MINUS_EXPR, type, vr0max, vr1min))
+ return true;
+
+ /* If op1 is not negative, op0 - op1 in infinite precision for op0 < op1
+ will be always in [-inf, -1] and so will always overflow if type is
+ unsigned. */
+ if (rel == VREL_LT
+ && tree_int_cst_sgn (vr1min) >= 0
+ && TYPE_UNSIGNED (type))
+ {
+ *ovf = true;
+ return true;
+ }
+
*ovf = arith_overflowed_p (subcode, type, vr0min,
subcode == MINUS_EXPR ? vr1max : vr1min);
if (arith_overflowed_p (subcode, type, vr0max,