Fix MINUS_EXPR relations.

Flesh out and correct relations for both wrapping and non-wrapping values.

	gcc/
	PR tree-optimization/101254
	* range-op.cc (operator_minus::op1_op2_relation_effect): Check for
	wrapping/non-wrapping when setting the result range.

	gcc/testsuite
	* gcc.dg/pr101254.c: New.
This commit is contained in:
Andrew MacLeod 2021-06-29 10:52:58 -04:00
parent 604dce2d74
commit a96d8d67d0
2 changed files with 74 additions and 17 deletions

View File

@ -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;

View File

@ -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;
}