virtual bool op1_range (irange &r, tree type,
const irange &lhs,
const irange &op2) const;
+ virtual bool op2_range (irange &r, tree type,
+ const irange &lhs,
+ const irange &op1) const;
} op_trunc_mod;
void
bool
operator_trunc_mod::op1_range (irange &r, tree type,
const irange &lhs,
- const irange &op2) const
+ const irange &) const
{
- // PR 91029. Check for signed truncation with op2 >= 0.
- if (TYPE_SIGN (type) == SIGNED && wi::ge_p (op2.lower_bound (), 0, SIGNED))
+ // PR 91029.
+ signop sign = TYPE_SIGN (type);
+ unsigned prec = TYPE_PRECISION (type);
+ // (a % b) >= x && x > 0 , then a >= x.
+ if (wi::gt_p (lhs.lower_bound (), 0, sign))
{
- unsigned prec = TYPE_PRECISION (type);
- // if a % b > 0 , then a >= 0.
- if (wi::gt_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;
- }
+ r = value_range (type, lhs.lower_bound (), wi::max_value (prec, sign));
+ return true;
+ }
+ // (a % b) <= x && x < 0 , then a <= x.
+ if (wi::lt_p (lhs.upper_bound (), 0, sign))
+ {
+ r = value_range (type, wi::min_value (prec, sign), lhs.upper_bound ());
+ return true;
+ }
+ return false;
+}
+
+bool
+operator_trunc_mod::op2_range (irange &r, tree type,
+ const irange &lhs,
+ const irange &) const
+{
+ // PR 91029.
+ signop sign = TYPE_SIGN (type);
+ unsigned prec = TYPE_PRECISION (type);
+ // (a % b) >= x && x > 0 , then b is in ~[-x, x] for signed
+ // or b > x for unsigned.
+ if (wi::gt_p (lhs.lower_bound (), 0, sign))
+ {
+ if (sign == SIGNED)
+ r = value_range (type, wi::neg (lhs.lower_bound ()),
+ lhs.lower_bound (), VR_ANTI_RANGE);
+ else if (wi::lt_p (lhs.lower_bound (), wi::max_value (prec, sign),
+ sign))
+ r = value_range (type, lhs.lower_bound () + 1,
+ wi::max_value (prec, sign));
+ else
+ return false;
+ return true;
+ }
+ // (a % b) <= x && x < 0 , then b is in ~[x, -x].
+ if (wi::lt_p (lhs.upper_bound (), 0, sign))
+ {
+ if (wi::gt_p (lhs.upper_bound (), wi::min_value (prec, sign), sign))
+ r = value_range (type, lhs.upper_bound (),
+ wi::neg (lhs.upper_bound ()), VR_ANTI_RANGE);
+ else
+ return false;
+ return true;
}
return false;
}
--- /dev/null
+/* PR tree-optimization/91029 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp" } */
+
+void kill (void);
+int xx;
+
+void f1 (int i, int j)
+{
+ if ((i % j) == 3)
+ {
+ xx = (j <= 3 && j >= -3);
+ if (xx)
+ kill ();
+ }
+}
+
+void f2 (int i, int j)
+{
+ if ((i % j) > 0)
+ {
+ xx = (j <= 1 && j >= -1);
+ if (xx)
+ kill ();
+ }
+}
+
+void f3 (int i, int j)
+{
+ if ((i % j) == -3)
+ {
+ xx = (j <= 3 && j >= -3);
+ if (xx)
+ kill ();
+ }
+}
+
+void f4 (int i, int j)
+{
+ if ((i % j) < 0)
+ {
+ xx = (j <= 1 && j >= -1);
+ if (xx)
+ kill ();
+ }
+}
+
+void f5 (int i, int j)
+{
+ if ((i % j) > 42)
+ {
+ xx = (j <= 43 && j >= -43);
+ if (xx)
+ kill ();
+ }
+}
+
+void f6 (int i, int j)
+{
+ if ((i % j) < -124)
+ {
+ xx = (j <= 125 && j >= -125);
+ if (xx)
+ kill ();
+ }
+}
+
+void f7 (unsigned int i, unsigned int j)
+{
+ if ((i % j) == 3)
+ {
+ xx = (j <= 3);
+ if (xx)
+ kill ();
+ }
+}
+
+void f8 (unsigned int i, unsigned int j)
+{
+ if ((i % j) > 0)
+ {
+ xx = (j <= 1);
+ if (xx)
+ kill ();
+ }
+}
+
+void f9 (unsigned int i, unsigned int j)
+{
+ if ((i % j) >= 124)
+ {
+ xx = (j <= 124);
+ if (xx)
+ kill ();
+ }
+}
+
+/* { dg-final { scan-tree-dump-not "kill" "evrp" } } */