diff options
author | Andrew MacLeod <amacleod@redhat.com> | 2021-06-17 13:35:10 -0400 |
---|---|---|
committer | Andrew MacLeod <amacleod@redhat.com> | 2021-06-22 08:11:45 -0400 |
commit | c526de3f432a037bdbdd44eb6fa43af4f3b22694 (patch) | |
tree | 961ae1b7eebb2d9ca3658c19f977b84713d80dee /gcc | |
parent | a2c9173331914eff3d728c07afaeee71892689ba (diff) | |
download | gcc-c526de3f432a037bdbdd44eb6fa43af4f3b22694.zip gcc-c526de3f432a037bdbdd44eb6fa43af4f3b22694.tar.gz gcc-c526de3f432a037bdbdd44eb6fa43af4f3b22694.tar.bz2 |
Add relations between LHS and op1/op2 for PLUS_EXPR.
* range-op.cc (operator_plus::lhs_op1_relation): New.
(operator_plus::lhs_op2_relation): New.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/range-op.cc | 80 |
1 files changed, 80 insertions, 0 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc index d807693..a7698f2 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -1150,8 +1150,88 @@ public: const wide_int &lh_ub, const wide_int &rh_lb, const wide_int &rh_ub) const; + virtual enum tree_code lhs_op1_relation (const irange &lhs, const irange &op1, + const irange &op2) const; + virtual enum tree_code lhs_op2_relation (const irange &lhs, const irange &op1, + const irange &op2) const; } op_plus; +// Check to see if the range of OP2 indicates anything about the relation +// between LHS and OP1. + +enum tree_code +operator_plus::lhs_op1_relation (const irange &lhs, + const irange &op1, + const irange &op2) const +{ + if (lhs.undefined_p () || op1.undefined_p () || op2.undefined_p ()) + return VREL_NONE; + + tree type = lhs.type (); + unsigned prec = TYPE_PRECISION (type); + wi::overflow_type ovf1, ovf2; + signop sign = TYPE_SIGN (type); + + // LHS = OP1 + 0 indicates LHS == OP1. + if (op2.zero_p ()) + return EQ_EXPR; + + if (TYPE_OVERFLOW_WRAPS (type)) + { + wi::add (op1.lower_bound (), op2.lower_bound (), sign, &ovf1); + wi::add (op1.upper_bound (), op2.upper_bound (), sign, &ovf2); + } + else + ovf1 = ovf2 = wi::OVF_NONE; + + // Never wrapping additions. + if (!ovf1 && !ovf2) + { + // Positive op2 means lhs > op1. + if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign)) + return GT_EXPR; + if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign)) + return GE_EXPR; + + // Negative op2 means lhs < op1. + if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign)) + return LT_EXPR; + if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign)) + return LE_EXPR; + } + // Always wrapping additions. + else if (ovf1 && ovf1 == ovf2) + { + // Positive op2 means lhs < op1. + if (wi::gt_p (op2.lower_bound (), wi::zero (prec), sign)) + return LT_EXPR; + if (wi::ge_p (op2.lower_bound (), wi::zero (prec), sign)) + return LE_EXPR; + + // Negative op2 means lhs > op1. + if (wi::lt_p (op2.upper_bound (), wi::zero (prec), sign)) + return GT_EXPR; + if (wi::le_p (op2.upper_bound (), wi::zero (prec), sign)) + return GE_EXPR; + } + + // If op2 does not contain 0, then LHS and OP1 can never be equal. + if (!range_includes_zero_p (&op2)) + return NE_EXPR; + + return VREL_NONE; +} + +// PLUS is symmetrical, so we can simply call lhs_op1_relation with reversed +// operands. + +enum tree_code +operator_plus::lhs_op2_relation (const irange &lhs, const irange &op1, + const irange &op2) const +{ + return lhs_op1_relation (lhs, op2, op1); +} + void operator_plus::wi_fold (irange &r, tree type, const wide_int &lh_lb, const wide_int &lh_ub, |