recognize implied ranges for modulo.

implement op1_range for modulo with implied positive and negative ranges.

	gcc/
	PR tree-optimization/91029
	* range-op.cc (operator_trunc_mod::op1_range): New.
	gcc/testsuite/
	* gcc.dg/pr91029.c: New.
This commit is contained in:
Andrew MacLeod 2020-11-17 14:47:58 -05:00
parent 0c1db9fa47
commit 1e27e7a582
2 changed files with 75 additions and 0 deletions

View file

@ -2634,6 +2634,9 @@ public:
const wide_int &lh_ub,
const wide_int &rh_lb,
const wide_int &rh_ub) const;
virtual bool op1_range (irange &r, tree type,
const irange &lhs,
const irange &op2) const;
} op_trunc_mod;
void
@ -2680,6 +2683,31 @@ operator_trunc_mod::wi_fold (irange &r, tree type,
value_range_with_overflow (r, type, new_lb, new_ub);
}
bool
operator_trunc_mod::op1_range (irange &r, tree type,
const irange &lhs,
const irange &op2) const
{
// PR 91029. Check for signed truncation with op2 >= 0.
if (TYPE_SIGN (type) == SIGNED && wi::ge_p (op2.lower_bound (), 0, SIGNED))
{
unsigned prec = TYPE_PRECISION (type);
// if a & b >=0 , then a >= 0.
if (wi::ge_p (lhs.lower_bound (), 0, SIGNED))
{
r = value_range (type, wi::zero (prec), wi::max_value (prec, SIGNED));
return true;
}
// if a & b < 0 , then a <= 0.
if (wi::lt_p (lhs.upper_bound (), 0, SIGNED))
{
r = value_range (type, wi::min_value (prec, SIGNED), wi::zero (prec));
return true;
}
}
return false;
}
class operator_logical_not : public range_operator
{

View file

@ -0,0 +1,47 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-tree-evrp" } */
void kill (void);
int xx;
void f1 (int i)
{
if ((i % 7) == 3)
{
xx = (i < 0);
if (xx)
kill ();
}
}
void f2 (int i)
{
if ((i % 7) >= 0)
{
xx = (i < 0);
if (xx)
kill ();
}
}
void f3 (int i)
{
if ((i % 7) == -3)
{
xx = (i > 0);
if (xx)
kill ();
}
}
void f4 (int i)
{
if ((i % 7) < 0)
{
xx = (i > 0);
if (xx)
kill ();
}
}
/* { dg-final { scan-tree-dump-not "kill" "evrp" } } */