diff --git a/gcc/range-op.cc b/gcc/range-op.cc index 29ee9e0f645..97b9843e095 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -1314,24 +1314,54 @@ operator_minus::op1_op2_relation_effect (irange &lhs_range, tree type, unsigned prec = TYPE_PRECISION (type); signop sgn = TYPE_SIGN (type); - switch (rel) + // == and != produce [0,0] and ~[0,0] regardless of wrapping. + if (rel == EQ_EXPR) + rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec)); + else if (rel == NE_EXPR) + rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec), + VR_ANTI_RANGE); + else if (TYPE_OVERFLOW_WRAPS (type)) { - // op1 > op2, op1 - op2 can be restricted to [1, max] - case GT_EXPR: - rel_range = int_range<2> (type, wi::one (prec), - wi::max_value (prec, sgn)); - break; - // op1 >= op2, op1 - op2 can be restricted to [0, max] - case GE_EXPR: - rel_range = int_range<2> (type, wi::zero (prec), - wi::max_value (prec, sgn)); - break; - // op1 == op2, op1 - op2 can be restricted to [0, 0] - case EQ_EXPR: - rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec)); - break; - default: - return false; + switch (rel) + { + // For wrapping signed values and unsigned, if op1 > op2 or + // op1 < op2, then op1 - op2 can be restricted to ~[0, 0]. + case GT_EXPR: + case LT_EXPR: + rel_range = int_range<2> (type, wi::zero (prec), wi::zero (prec), + VR_ANTI_RANGE); + break; + default: + return false; + } + } + else + { + switch (rel) + { + // op1 > op2, op1 - op2 can be restricted to [1, +INF] + case GT_EXPR: + rel_range = int_range<2> (type, wi::one (prec), + wi::max_value (prec, sgn)); + break; + // op1 >= op2, op1 - op2 can be restricted to [0, +INF] + case GE_EXPR: + rel_range = int_range<2> (type, wi::zero (prec), + wi::max_value (prec, sgn)); + break; + // op1 < op2, op1 - op2 can be restricted to [-INF, -1] + case LT_EXPR: + rel_range = int_range<2> (type, wi::min_value (prec, sgn), + wi::minus_one (prec)); + break; + // op1 <= op2, op1 - op2 can be restricted to [-INF, 0] + case LE_EXPR: + rel_range = int_range<2> (type, wi::min_value (prec, sgn), + wi::zero (prec)); + break; + default: + return false; + } } lhs_range.intersect (rel_range); return true; diff --git a/gcc/testsuite/gcc.dg/pr101254.c b/gcc/testsuite/gcc.dg/pr101254.c new file mode 100644 index 00000000000..b2460ed86f3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr101254.c @@ -0,0 +1,27 @@ +/* PR tree-optimization/101254 */ +/* { dg-do run } */ +/* { dg-options "-O2 -fwrapv" } */ + +int +foo (long long imin, long long imax) +{ + if (imin > imax) + return 0; + else if (imax - imin < 0 || (imax - imin) + 1 < 0) + return 0; + return 1; +} + +int +main () +{ + long long imax = __LONG_LONG_MAX__; + long long imin = -imax - 1; + if (!foo (-10, 10)) + __builtin_abort (); + if (foo (-10, imax)) + __builtin_abort (); + if (foo (imin, imax)) + __builtin_abort (); + return 0; +}