* [COMMITTED] Move TRUE case first in range-op.cc. @ 2022-10-11 13:51 Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Share common ordered comparison code with UN*_EXPR Aldy Hernandez ` (2 more replies) 0 siblings, 3 replies; 5+ messages in thread From: Aldy Hernandez @ 2022-10-11 13:51 UTC (permalink / raw) To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez It's incredibly annoying that some of the BRS_TRUE cases come after BRS_FALSE, if only because we're not consistent. Having random ordering increases the changes of thinkos when adapting the irange code to floats. gcc/ChangeLog: * range-op.cc (operator_equal::op1_range): Move BRS_TRUE case up. (operator_lt::op2_range): Same. (operator_le::op2_range): Same. (operator_gt::op2_range): Same. (operator_ge::op2_range): Same. --- gcc/range-op.cc | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index df0735cb42a..4d5a033dfa5 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -531,6 +531,11 @@ operator_equal::op1_range (irange &r, tree type, { switch (get_bool_state (r, lhs, type)) { + case BRS_TRUE: + // If it's true, the result is the same as OP2. + r = op2; + break; + case BRS_FALSE: // If the result is false, the only time we know anything is // if OP2 is a constant. @@ -543,11 +548,6 @@ operator_equal::op1_range (irange &r, tree type, r.set_varying (type); break; - case BRS_TRUE: - // If it's true, the result is the same as OP2. - r = op2; - break; - default: break; } @@ -841,14 +841,14 @@ operator_lt::op2_range (irange &r, tree type, { switch (get_bool_state (r, lhs, type)) { - case BRS_FALSE: - build_le (r, type, op1.upper_bound ()); - break; - case BRS_TRUE: build_gt (r, type, op1.lower_bound ()); break; + case BRS_FALSE: + build_le (r, type, op1.upper_bound ()); + break; + default: break; } @@ -952,14 +952,14 @@ operator_le::op2_range (irange &r, tree type, { switch (get_bool_state (r, lhs, type)) { - case BRS_FALSE: - build_lt (r, type, op1.upper_bound ()); - break; - case BRS_TRUE: build_ge (r, type, op1.lower_bound ()); break; + case BRS_FALSE: + build_lt (r, type, op1.upper_bound ()); + break; + default: break; } @@ -1062,14 +1062,14 @@ operator_gt::op2_range (irange &r, tree type, { switch (get_bool_state (r, lhs, type)) { - case BRS_FALSE: - build_ge (r, type, op1.lower_bound ()); - break; - case BRS_TRUE: build_lt (r, type, op1.upper_bound ()); break; + case BRS_FALSE: + build_ge (r, type, op1.lower_bound ()); + break; + default: break; } @@ -1173,14 +1173,14 @@ operator_ge::op2_range (irange &r, tree type, { switch (get_bool_state (r, lhs, type)) { - case BRS_FALSE: - build_gt (r, type, op1.lower_bound ()); - break; - case BRS_TRUE: build_le (r, type, op1.upper_bound ()); break; + case BRS_FALSE: + build_gt (r, type, op1.lower_bound ()); + break; + default: break; } -- 2.37.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [COMMITTED] Share common ordered comparison code with UN*_EXPR. 2022-10-11 13:51 [COMMITTED] Move TRUE case first in range-op.cc Aldy Hernandez @ 2022-10-11 13:51 ` Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement op1_range operators for unordered comparisons Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement ABS_EXPR operator for frange Aldy Hernandez 2 siblings, 0 replies; 5+ messages in thread From: Aldy Hernandez @ 2022-10-11 13:51 UTC (permalink / raw) To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez Most unordered comparisons can use the result from the ordered version, if the operands are known not to be NAN or if the result is true. gcc/ChangeLog: * range-op-float.cc (class foperator_unordered_lt): New. (class foperator_relop_unknown): Remove (class foperator_unordered_le): New. (class foperator_unordered_gt): New. (class foperator_unordered_ge): New. (class foperator_unordered_equal): New. (floating_op_table::floating_op_table): Replace all UN_EXPR entries with their appropriate fop_unordered_* counterpart. --- gcc/range-op-float.cc | 140 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 12 deletions(-) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 3cf117d8931..8dd4bcc70c0 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -1132,24 +1132,140 @@ foperator_ordered::op1_range (frange &r, tree type, return true; } -// Placeholder for unimplemented relational operators. +class foperator_unordered_lt : public range_operator_float +{ + using range_operator_float::fold_range; +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + if (op1.known_isnan () || op2.known_isnan ()) + { + r = range_true (type); + return true; + } + if (!fop_lt.fold_range (r, type, op1, op2, rel)) + return false; + // The result is the same as the ordered version when the + // comparison is true or when the operands cannot be NANs. + if (finite_operands_p (op1, op2) || r == range_true (type)) + return true; + else + { + r = range_true_and_false (type); + return true; + } + } +} fop_unordered_lt; -class foperator_relop_unknown : public range_operator_float +class foperator_unordered_le : public range_operator_float { using range_operator_float::fold_range; +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + if (op1.known_isnan () || op2.known_isnan ()) + { + r = range_true (type); + return true; + } + if (!fop_le.fold_range (r, type, op1, op2, rel)) + return false; + // The result is the same as the ordered version when the + // comparison is true or when the operands cannot be NANs. + if (finite_operands_p (op1, op2) || r == range_true (type)) + return true; + else + { + r = range_true_and_false (type); + return true; + } + } +} fop_unordered_le; +class foperator_unordered_gt : public range_operator_float +{ + using range_operator_float::fold_range; public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, - relation_kind) const final override + relation_kind rel) const final override { if (op1.known_isnan () || op2.known_isnan ()) - r = range_true (type); + { + r = range_true (type); + return true; + } + if (!fop_gt.fold_range (r, type, op1, op2, rel)) + return false; + // The result is the same as the ordered version when the + // comparison is true or when the operands cannot be NANs. + if (finite_operands_p (op1, op2) || r == range_true (type)) + return true; else - r.set_varying (type); - return true; + { + r = range_true_and_false (type); + return true; + } + } +} fop_unordered_gt; + +class foperator_unordered_ge : public range_operator_float +{ + using range_operator_float::fold_range; +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + if (op1.known_isnan () || op2.known_isnan ()) + { + r = range_true (type); + return true; + } + if (!fop_ge.fold_range (r, type, op1, op2, rel)) + return false; + // The result is the same as the ordered version when the + // comparison is true or when the operands cannot be NANs. + if (finite_operands_p (op1, op2) || r == range_true (type)) + return true; + else + { + r = range_true_and_false (type); + return true; + } + } +} fop_unordered_ge; + +class foperator_unordered_equal : public range_operator_float +{ + using range_operator_float::fold_range; +public: + bool fold_range (irange &r, tree type, + const frange &op1, const frange &op2, + relation_kind rel) const final override + { + if (op1.known_isnan () || op2.known_isnan ()) + { + r = range_true (type); + return true; + } + if (!fop_equal.fold_range (r, type, op1, op2, rel)) + return false; + // The result is the same as the ordered version when the + // comparison is true or when the operands cannot be NANs. + if (finite_operands_p (op1, op2) || r == range_true (type)) + return true; + else + { + r = range_true_and_false (type); + return true; + } } -} fop_unordered_relop_unknown; +} fop_unordered_equal; // Instantiate a range_op_table for floating point operations. @@ -1174,11 +1290,11 @@ floating_op_table::floating_op_table () set (LE_EXPR, fop_le); set (GT_EXPR, fop_gt); set (GE_EXPR, fop_ge); - set (UNLE_EXPR, fop_unordered_relop_unknown); - set (UNLT_EXPR, fop_unordered_relop_unknown); - set (UNGE_EXPR, fop_unordered_relop_unknown); - set (UNGT_EXPR, fop_unordered_relop_unknown); - set (UNEQ_EXPR, fop_unordered_relop_unknown); + set (UNLE_EXPR, fop_unordered_le); + set (UNLT_EXPR, fop_unordered_lt); + set (UNGE_EXPR, fop_unordered_ge); + set (UNGT_EXPR, fop_unordered_gt); + set (UNEQ_EXPR, fop_unordered_equal); set (ORDERED_EXPR, fop_ordered); set (UNORDERED_EXPR, fop_unordered); } -- 2.37.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
* [COMMITTED] Implement op1_range operators for unordered comparisons. 2022-10-11 13:51 [COMMITTED] Move TRUE case first in range-op.cc Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Share common ordered comparison code with UN*_EXPR Aldy Hernandez @ 2022-10-11 13:51 ` Aldy Hernandez 2022-10-11 13:57 ` Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement ABS_EXPR operator for frange Aldy Hernandez 2 siblings, 1 reply; 5+ messages in thread From: Aldy Hernandez @ 2022-10-11 13:51 UTC (permalink / raw) To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez gcc/ChangeLog: * range-op-float.cc (foperator_unordered_le::op1_range): New. (foperator_unordered_le::op2_range): New. (foperator_unordered_gt::op1_range): New. (foperator_unordered_gt::op2_range): New. (foperator_unordered_ge::op1_range): New. (foperator_unordered_ge::op2_range): New. (foperator_unordered_equal::op1_range): New. --- gcc/range-op-float.cc | 205 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index 8dd4bcc70c0..ef51b7538e3 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -1162,6 +1162,8 @@ public: class foperator_unordered_le : public range_operator_float { using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, @@ -1184,11 +1186,65 @@ public: return true; } } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override; } fop_unordered_le; +bool +foperator_unordered_le::op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_le (r, type, op2); + break; + + case BRS_FALSE: + build_gt (r, type, op2); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + +bool +foperator_unordered_le::op2_range (frange &r, + tree type, + const irange &lhs, + const frange &op1, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_ge (r, type, op1); + break; + + case BRS_FALSE: + build_lt (r, type, op1); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + class foperator_unordered_gt : public range_operator_float { using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, @@ -1211,11 +1267,67 @@ public: return true; } } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override; } fop_unordered_gt; +bool +foperator_unordered_gt::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_gt (r, type, op2); + break; + + case BRS_FALSE: + build_le (r, type, op2); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + +bool +foperator_unordered_gt::op2_range (frange &r, + tree type, + const irange &lhs, + const frange &op1, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_lt (r, type, op1); + break; + + case BRS_FALSE: + build_ge (r, type, op1); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + class foperator_unordered_ge : public range_operator_float { using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, @@ -1238,11 +1350,66 @@ public: return true; } } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override; } fop_unordered_ge; +bool +foperator_unordered_ge::op1_range (frange &r, + tree type, + const irange &lhs, + const frange &op2, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_ge (r, type, op2); + break; + + case BRS_FALSE: + build_lt (r, type, op2); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + +bool +foperator_unordered_ge::op2_range (frange &r, tree type, + const irange &lhs, + const frange &op1, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + build_le (r, type, op1); + break; + + case BRS_FALSE: + build_gt (r, type, op1); + r.clear_nan (); + break; + + default: + break; + } + return true; +} + class foperator_unordered_equal : public range_operator_float { using range_operator_float::fold_range; + using range_operator_float::op1_range; + using range_operator_float::op2_range; public: bool fold_range (irange &r, tree type, const frange &op1, const frange &op2, @@ -1265,8 +1432,46 @@ public: return true; } } + bool op1_range (frange &r, tree type, + const irange &lhs, const frange &op2, + relation_kind rel) const final override; + bool op2_range (frange &r, tree type, + const irange &lhs, const frange &op1, + relation_kind rel) const final override + { + return op1_range (r, type, lhs, op1, rel); + } } fop_unordered_equal; +bool +foperator_unordered_equal::op1_range (frange &r, tree type, + const irange &lhs, + const frange &op2, + relation_kind) const +{ + switch (get_bool_state (r, lhs, type)) + { + case BRS_TRUE: + // If it's true, the result is the same as OP2 plus a NAN. + r = op2; + // Add both zeros if there's the possibility of zero equality. + frange_add_zeros (r, type); + // Add the posibility of a NAN. + r.update_nan (); + break; + + case BRS_FALSE: + // The false side indictates !NAN and not equal. We can at least + // represent !NAN. + r.set_varying (type); + r.clear_nan (); + break; + + default: + break; + } + return true; +} // Instantiate a range_op_table for floating point operations. static floating_op_table global_floating_table; -- 2.37.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [COMMITTED] Implement op1_range operators for unordered comparisons. 2022-10-11 13:51 ` [COMMITTED] Implement op1_range operators for unordered comparisons Aldy Hernandez @ 2022-10-11 13:57 ` Aldy Hernandez 0 siblings, 0 replies; 5+ messages in thread From: Aldy Hernandez @ 2022-10-11 13:57 UTC (permalink / raw) To: GCC patches; +Cc: Andrew MacLeod I forgot to mention. These were lifted from the integer counterparts. Most of the code is the same, as the build_{cond} code in the frange version will add the appropriate NAN (unless -ffinite-math-only), and all we have to do is clear it on the false edge. Aldy On Tue, Oct 11, 2022 at 3:51 PM Aldy Hernandez <aldyh@redhat.com> wrote: > > gcc/ChangeLog: > > * range-op-float.cc (foperator_unordered_le::op1_range): New. > (foperator_unordered_le::op2_range): New. > (foperator_unordered_gt::op1_range): New. > (foperator_unordered_gt::op2_range): New. > (foperator_unordered_ge::op1_range): New. > (foperator_unordered_ge::op2_range): New. > (foperator_unordered_equal::op1_range): New. > --- > gcc/range-op-float.cc | 205 ++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 205 insertions(+) > > diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc > index 8dd4bcc70c0..ef51b7538e3 100644 > --- a/gcc/range-op-float.cc > +++ b/gcc/range-op-float.cc > @@ -1162,6 +1162,8 @@ public: > class foperator_unordered_le : public range_operator_float > { > using range_operator_float::fold_range; > + using range_operator_float::op1_range; > + using range_operator_float::op2_range; > public: > bool fold_range (irange &r, tree type, > const frange &op1, const frange &op2, > @@ -1184,11 +1186,65 @@ public: > return true; > } > } > + bool op1_range (frange &r, tree type, > + const irange &lhs, const frange &op2, > + relation_kind rel) const final override; > + bool op2_range (frange &r, tree type, > + const irange &lhs, const frange &op1, > + relation_kind rel) const final override; > } fop_unordered_le; > > +bool > +foperator_unordered_le::op1_range (frange &r, tree type, > + const irange &lhs, const frange &op2, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_le (r, type, op2); > + break; > + > + case BRS_FALSE: > + build_gt (r, type, op2); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > +bool > +foperator_unordered_le::op2_range (frange &r, > + tree type, > + const irange &lhs, > + const frange &op1, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_ge (r, type, op1); > + break; > + > + case BRS_FALSE: > + build_lt (r, type, op1); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > class foperator_unordered_gt : public range_operator_float > { > using range_operator_float::fold_range; > + using range_operator_float::op1_range; > + using range_operator_float::op2_range; > public: > bool fold_range (irange &r, tree type, > const frange &op1, const frange &op2, > @@ -1211,11 +1267,67 @@ public: > return true; > } > } > + bool op1_range (frange &r, tree type, > + const irange &lhs, const frange &op2, > + relation_kind rel) const final override; > + bool op2_range (frange &r, tree type, > + const irange &lhs, const frange &op1, > + relation_kind rel) const final override; > } fop_unordered_gt; > > +bool > +foperator_unordered_gt::op1_range (frange &r, > + tree type, > + const irange &lhs, > + const frange &op2, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_gt (r, type, op2); > + break; > + > + case BRS_FALSE: > + build_le (r, type, op2); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > +bool > +foperator_unordered_gt::op2_range (frange &r, > + tree type, > + const irange &lhs, > + const frange &op1, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_lt (r, type, op1); > + break; > + > + case BRS_FALSE: > + build_ge (r, type, op1); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > class foperator_unordered_ge : public range_operator_float > { > using range_operator_float::fold_range; > + using range_operator_float::op1_range; > + using range_operator_float::op2_range; > public: > bool fold_range (irange &r, tree type, > const frange &op1, const frange &op2, > @@ -1238,11 +1350,66 @@ public: > return true; > } > } > + bool op1_range (frange &r, tree type, > + const irange &lhs, const frange &op2, > + relation_kind rel) const final override; > + bool op2_range (frange &r, tree type, > + const irange &lhs, const frange &op1, > + relation_kind rel) const final override; > } fop_unordered_ge; > > +bool > +foperator_unordered_ge::op1_range (frange &r, > + tree type, > + const irange &lhs, > + const frange &op2, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_ge (r, type, op2); > + break; > + > + case BRS_FALSE: > + build_lt (r, type, op2); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > +bool > +foperator_unordered_ge::op2_range (frange &r, tree type, > + const irange &lhs, > + const frange &op1, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + build_le (r, type, op1); > + break; > + > + case BRS_FALSE: > + build_gt (r, type, op1); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > + > class foperator_unordered_equal : public range_operator_float > { > using range_operator_float::fold_range; > + using range_operator_float::op1_range; > + using range_operator_float::op2_range; > public: > bool fold_range (irange &r, tree type, > const frange &op1, const frange &op2, > @@ -1265,8 +1432,46 @@ public: > return true; > } > } > + bool op1_range (frange &r, tree type, > + const irange &lhs, const frange &op2, > + relation_kind rel) const final override; > + bool op2_range (frange &r, tree type, > + const irange &lhs, const frange &op1, > + relation_kind rel) const final override > + { > + return op1_range (r, type, lhs, op1, rel); > + } > } fop_unordered_equal; > > +bool > +foperator_unordered_equal::op1_range (frange &r, tree type, > + const irange &lhs, > + const frange &op2, > + relation_kind) const > +{ > + switch (get_bool_state (r, lhs, type)) > + { > + case BRS_TRUE: > + // If it's true, the result is the same as OP2 plus a NAN. > + r = op2; > + // Add both zeros if there's the possibility of zero equality. > + frange_add_zeros (r, type); > + // Add the posibility of a NAN. > + r.update_nan (); > + break; > + > + case BRS_FALSE: > + // The false side indictates !NAN and not equal. We can at least > + // represent !NAN. > + r.set_varying (type); > + r.clear_nan (); > + break; > + > + default: > + break; > + } > + return true; > +} > > // Instantiate a range_op_table for floating point operations. > static floating_op_table global_floating_table; > -- > 2.37.3 > ^ permalink raw reply [flat|nested] 5+ messages in thread
* [COMMITTED] Implement ABS_EXPR operator for frange. 2022-10-11 13:51 [COMMITTED] Move TRUE case first in range-op.cc Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Share common ordered comparison code with UN*_EXPR Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement op1_range operators for unordered comparisons Aldy Hernandez @ 2022-10-11 13:51 ` Aldy Hernandez 2 siblings, 0 replies; 5+ messages in thread From: Aldy Hernandez @ 2022-10-11 13:51 UTC (permalink / raw) To: GCC patches; +Cc: Andrew MacLeod, Aldy Hernandez Implementing ABS_EXPR allows us to fold certain __builtin_inf calls since they are expanded into calls to involving ABS_EXPR. This is an adaptation of the integer version. gcc/ChangeLog: * range-op-float.cc (class foperator_abs): New. (floating_op_table::floating_op_table): Add ABS_EXPR entry. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/vrp-float-abs-1.c: New test. --- gcc/range-op-float.cc | 91 +++++++++++++++++++ .../gcc.dg/tree-ssa/vrp-float-abs-1.c | 17 ++++ 2 files changed, 108 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c diff --git a/gcc/range-op-float.cc b/gcc/range-op-float.cc index ef51b7538e3..283eb134c78 100644 --- a/gcc/range-op-float.cc +++ b/gcc/range-op-float.cc @@ -1132,6 +1132,95 @@ foperator_ordered::op1_range (frange &r, tree type, return true; } +class foperator_abs : public range_operator_float +{ + using range_operator_float::fold_range; + using range_operator_float::op1_range; +public: + bool fold_range (frange &r, tree type, + const frange &op1, const frange &, + relation_kind) const final override; + bool op1_range (frange &r, tree type, + const frange &lhs, const frange &op2, + relation_kind rel) const final override; +} fop_abs; + +bool +foperator_abs::fold_range (frange &r, tree type, + const frange &op1, const frange &op2, + relation_kind) const +{ + if (empty_range_varying (r, type, op1, op2)) + return true; + if (op1.known_isnan ()) + { + r.set_nan (type, /*sign=*/false); + return true; + } + + const REAL_VALUE_TYPE lh_lb = op1.lower_bound (); + const REAL_VALUE_TYPE lh_ub = op1.upper_bound (); + // Handle the easy case where everything is positive. + if (real_compare (GE_EXPR, &lh_lb, &dconst0) + && !real_iszero (&lh_lb, /*sign=*/true) + && !op1.maybe_isnan (/*sign=*/true)) + { + r = op1; + return true; + } + + REAL_VALUE_TYPE min = real_value_abs (&lh_lb); + REAL_VALUE_TYPE max = real_value_abs (&lh_ub); + // If the range contains zero then we know that the minimum value in the + // range will be zero. + if (real_compare (LE_EXPR, &lh_lb, &dconst0) + && real_compare (GE_EXPR, &lh_ub, &dconst0)) + { + if (real_compare (GT_EXPR, &min, &max)) + max = min; + min = dconst0; + } + else + { + // If the range was reversed, swap MIN and MAX. + if (real_compare (GT_EXPR, &min, &max)) + std::swap (min, max); + } + + r.set (type, min, max); + if (op1.maybe_isnan ()) + r.update_nan (/*sign=*/false); + else + r.clear_nan (); + return true; +} + +bool +foperator_abs::op1_range (frange &r, tree type, + const frange &lhs, const frange &op2, + relation_kind) const +{ + if (empty_range_varying (r, type, lhs, op2)) + return true; + if (lhs.known_isnan ()) + { + r.set_nan (type); + return true; + } + + // Start with the positives because negatives are an impossible result. + frange positives (type, dconst0, frange_val_max (type)); + positives.update_nan (/*sign=*/false); + positives.intersect (lhs); + r = positives; + // Then add the negative of each pair: + // ABS(op1) = [5,20] would yield op1 => [-20,-5][5,20]. + r.union_ (frange (type, + real_value_negate (&positives.upper_bound ()), + real_value_negate (&positives.lower_bound ()))); + return true; +} + class foperator_unordered_lt : public range_operator_float { using range_operator_float::fold_range; @@ -1502,6 +1591,8 @@ floating_op_table::floating_op_table () set (UNEQ_EXPR, fop_unordered_equal); set (ORDERED_EXPR, fop_ordered); set (UNORDERED_EXPR, fop_unordered); + + set (ABS_EXPR, fop_abs); } // Return a pointer to the range_operator_float instance, if there is diff --git a/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c new file mode 100644 index 00000000000..4b7b75833e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-float-abs-1.c @@ -0,0 +1,17 @@ +// { dg-do compile } +// { dg-options "-O2 -fno-thread-jumps -fdump-tree-evrp" } + +void link_error (); + +void +foo (double x, double y) +{ + if (x > y && __builtin_signbit (y) == 0) + { + // y == +INF is impossible. + if (__builtin_isinf (y)) + link_error (); + } +} + +// { dg-final { scan-tree-dump-not "link_error" "evrp" } } -- 2.37.3 ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2022-10-11 13:57 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2022-10-11 13:51 [COMMITTED] Move TRUE case first in range-op.cc Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Share common ordered comparison code with UN*_EXPR Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement op1_range operators for unordered comparisons Aldy Hernandez 2022-10-11 13:57 ` Aldy Hernandez 2022-10-11 13:51 ` [COMMITTED] Implement ABS_EXPR operator for frange Aldy Hernandez
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).